From c4f2d719b74c44cbb025b1d175c0d9cf0cefcd46 Mon Sep 17 00:00:00 2001 From: Sebastien GOYON <shinedday@gmail.com> Date: Tue, 28 Jun 2022 15:12:18 +0200 Subject: [PATCH] Add SM agent and basic ants --- .gitignore | 6 + README.md | 92 +++++++ amakaque/Env.java | 233 ++++++++++++++++ amakaque/Group.java | 57 ++++ amakaque/MainAmakaque.java | 162 +++++++++++ amakaque/Phase.java | 10 + amakaque/SMAgent.java | 442 ++++++++++++++++++++++++++++++ amakaque/Scheduler.java | 26 ++ ant/Ant.java | 169 ++++++++++++ ant/Env.java | 106 +++++++ ant/MainAnt.java | 119 ++++++++ ant/Phase.java | 6 + ant/Scheduler.java | 28 ++ ant/Solution.java | 27 ++ baseOptiAgent/BaseAgent.java | 53 ++++ eval/Eval.java | 41 +++ eval/fun/Levy_function_1.java | 36 +++ eval/fun/Rastrigin.java | 39 +++ eval/fun/SchwefelFunction.java | 39 +++ eval/fun/SchwefelFunction1_2.java | 44 +++ eval/fun/StepFunction.java | 38 +++ 21 files changed, 1773 insertions(+) create mode 100644 README.md create mode 100644 amakaque/Env.java create mode 100644 amakaque/Group.java create mode 100644 amakaque/MainAmakaque.java create mode 100644 amakaque/Phase.java create mode 100644 amakaque/SMAgent.java create mode 100644 amakaque/Scheduler.java create mode 100644 ant/Ant.java create mode 100644 ant/Env.java create mode 100644 ant/MainAnt.java create mode 100644 ant/Phase.java create mode 100644 ant/Scheduler.java create mode 100644 ant/Solution.java create mode 100644 baseOptiAgent/BaseAgent.java create mode 100644 eval/Eval.java create mode 100644 eval/fun/Levy_function_1.java create mode 100644 eval/fun/Rastrigin.java create mode 100644 eval/fun/SchwefelFunction.java create mode 100644 eval/fun/SchwefelFunction1_2.java create mode 100644 eval/fun/StepFunction.java diff --git a/.gitignore b/.gitignore index 6b468b6..cecf43c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ *.class +.settings +.project +*.csv +.classpath +mas/ +example/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..a7705a5 --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# core + + + +## Getting started + +To make it easy for you to get started with GitLab, here's a list of recommended next steps. + +Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! + +## Add your files + +- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files +- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: + +``` +cd existing_repo +git remote add origin https://gitlab.irit.fr/smac/amak/java/core.git +git branch -M main +git push -uf origin main +``` + +## Integrate with your tools + +- [ ] [Set up project integrations](https://gitlab.irit.fr/smac/amak/java/core/-/settings/integrations) + +## Collaborate with your team + +- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) +- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) +- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) +- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) +- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) + +## Test and Deploy + +Use the built-in continuous integration in GitLab. + +- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) +- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) +- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) +- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) +- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) + +*** + +# Editing this README + +When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. + +## Suggestions for a good README +Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. + +## Name +Choose a self-explaining name for your project. + +## Description +Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. + +## Badges +On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. + +## Visuals +Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. + +## Installation +Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. + +## Usage +Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. + +## Support +Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. + +## Roadmap +If you have ideas for releases in the future, it is a good idea to list them in the README. + +## Contributing +State if you are open to contributions and what your requirements are for accepting them. + +For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. + +You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. + +## Authors and acknowledgment +Show your appreciation to those who have contributed to the project. + +## License +For open source projects, say how it is licensed. + +## Project status +If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. diff --git a/amakaque/Env.java b/amakaque/Env.java new file mode 100644 index 0000000..a7d2b1b --- /dev/null +++ b/amakaque/Env.java @@ -0,0 +1,233 @@ +package amakaque; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import eval.Eval; + +public class Env { + + + private int globalLimitCount; + private int localLimit; + private int globalLimit; + private int groupLimit; + private List<Group> groups; + + private Eval eval; + + public Env(int _localLimit, int _globalLimit, int _groupLimit, Eval _eval) { + globalLimitCount = 0; + eval = _eval; + + localLimit = _localLimit; + globalLimit = _globalLimit; + + groupLimit = _groupLimit; + + groups = new ArrayList<Group>(); + } + + public void initGroup(Group group) { + groups.add(group); + } + + public int getGlobalLimitCount() { + return globalLimitCount; + } + + public int getGlobalLimit() { + return globalLimit; + } + + public int getNbrGroup() { + return this.groups.size(); + } + + public int getGroupLimit() { + return this.groupLimit; + } + + public void addGlobalLimitCount() { + globalLimitCount ++; + } + + public void resetGlobalCount() { + globalLimitCount = 0; + } + + public List<Double> getRandomGroupMember(int i_group, int self_id) { + Group group = groups.get(i_group); + + Random rand = new Random(); + SMAgent randomagent = group.getAgents().get(rand.nextInt(group.getAgents().size())); + + if (group.getAgents().size() == 1) { + throw new java.lang.Error("The group :"+String.valueOf(i_group)+" only have 1 member."); + } + + while (randomagent.getId() == self_id) { + randomagent = group.getAgents().get(rand.nextInt(group.getAgents().size())); + } + + return randomagent.getDimVector(); + } + + public List<Double> getLocalLeader(int i_group){ + Group group = groups.get(i_group); + + List<SMAgent> agents = group.getAgents(); + for (SMAgent agent: agents) { + if(agent.isLL()) { + return agent.getDimVector(); + } + } + throw new java.lang.Error("The group :"+String.valueOf(i_group)+" don t have a local leader."); + } + + public double getMaxFitness() { + double max = 0; + + for (Group group: groups) { + for (SMAgent agent: group.getAgents()) { + double fitness = agent.getFitness(); + if(fitness > max) { + max = fitness; + } + } + } + return max; + } + + public List<Double> getGlobalLeader() { + + for (Group group: groups) { + for (SMAgent agent: group.getAgents()) { + if (agent.isGL()) { + return agent.getDimVector(); + } + } + } + throw new java.lang.Error("No global leader found."); + } + + public int getGroupSize(int i_group) { + return groups.get(i_group).getAgents().size(); + } + + public int getCount(int i_group) { + return groups.get(i_group).getCount(); + } + + public void count(int i_group) { + groups.get(i_group).count(); + } + + public void resetGroupCount(int i_group) { + groups.get(i_group).resetCount(); + } + + public boolean allDone() { + for (Group group: groups) { + if (group.getCount() < group.getAgents().size()) { + return false; + } + } + return true; + } + + public SMAgent findNextGL() { + SMAgent nextGL = null; + for (Group group: groups) { + for (SMAgent agent: group.getAgents()) { + if (nextGL == null) { + nextGL = agent; + } + else if (nextGL.getFitness() < agent.getFitness()) { + nextGL = agent; + } + } + } + return nextGL; + } + + public void addLocalLimit(int i_group) { + groups.get(i_group).addLocalLimit(); + } + + public SMAgent findNextLL(int i_group) { + SMAgent nextLL = null; + for (SMAgent agent: groups.get(i_group).getAgents()) { + if (nextLL == null) { + nextLL = agent; + } + else if (nextLL.getFitness() < agent.getFitness()) { + nextLL = agent; + + } + } + return nextLL; + } + + public int getLocalLimitCount(int i_group) { + return groups.get(i_group).getLocallimit(); + } + + public void resetLocalCount(int i_group) { + groups.get(i_group).resetLocalLimit(); + } + + public int getLocalLimit() { + return localLimit; + } + + public void combineAllGroups() { + while (groups.size() > 1) { + for(SMAgent agent: groups.get(1).getAgents()) { + agent.giveLocalLeadership(); + agent.enterNewGroup(0); + } + + groups.get(0).addAgents(groups.get(1).getAgents()); + groups.remove(1); + } + } + + public void splitInNGroups(int n) { + + for (int i = 0; i < n-1; i++) { + groups.add(new Group()); + } + + List<SMAgent> agents = new ArrayList<SMAgent>(); + agents.addAll(groups.get(0).getAgents()); + + for (SMAgent agent : agents) { + groups.get(0).removeAgent(agent); + } + + for (SMAgent agent : agents) { + agent.giveLocalLeadership(); + agent.enterNewGroup(agent.getId() % n); + List<SMAgent> list = new ArrayList<SMAgent>(); + list.add(agent); + groups.get(agent.getId() % n).addAgents(list); + } + } + + public List<Group> getGroups() { + return groups; + } + + public double getGLValue() { + for (Group group: groups) { + for (SMAgent agent: group.getAgents()) { + if (agent.isGL()) { + return agent.getFitness(); + } + } + } + throw new java.lang.Error("No global leader found."); + } +} diff --git a/amakaque/Group.java b/amakaque/Group.java new file mode 100644 index 0000000..beed888 --- /dev/null +++ b/amakaque/Group.java @@ -0,0 +1,57 @@ +package amakaque; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class Group { + + private AtomicInteger count; + private int localLimitCount; + + private List<SMAgent> agents; + + public Group() { + count = new AtomicInteger(1); + localLimitCount = 0; + agents = new ArrayList<SMAgent>(); + } + + public void count() { + count.getAndIncrement(); + } + + public int getCount() { + return count.intValue(); + } + + public void resetCount() { + count.set(1); + } + + public List<SMAgent> getAgents() { + return agents; + } + + public void removeAgent(SMAgent agent) { + agents.remove(agent); + } + + public void addAgents(List<SMAgent> _agents) { + for (SMAgent agent: _agents) { + agents.add(agent); + } + } + + public void addLocalLimit() { + localLimitCount ++; + } + + public void resetLocalLimit() { + localLimitCount = 0; + } + + public int getLocallimit() { + return this.localLimitCount; + } +} diff --git a/amakaque/MainAmakaque.java b/amakaque/MainAmakaque.java new file mode 100644 index 0000000..f8ac79a --- /dev/null +++ b/amakaque/MainAmakaque.java @@ -0,0 +1,162 @@ +package amakaque; + +import java.util.ArrayList; +import java.util.List; + +import eval.Eval; +import eval.fun.Levy_function_1; +import eval.fun.Rastrigin; +import eval.fun.SchwefelFunction; +import eval.fun.SchwefelFunction1_2; +import eval.fun.StepFunction; +import mas.core.Schedulable; + +public class MainAmakaque { + + public static void main(String[] args) { + // [PARAM] + + int nbrAgent = 50; + + // [0.1 : 0.9] + double pr = 0.1; + + // + int maxGroup = 5; + + int localLimit = 1500; + int globalLimit = 50; + + int res = 0; + int nbrTry = 100; + + long startTime = System.currentTimeMillis(); + for (int i = 0; i < nbrTry; i++) { + res += findSolution(nbrAgent, pr, maxGroup, localLimit, globalLimit); + // System.out.println("run : "+i); + } + long estimatedTime = System.currentTimeMillis() - startTime; + + System.out.println("Time : "+estimatedTime/1000+ "s "+estimatedTime%1000+"ms"); + // System.out.println(res); + System.out.println("Average cycle : "+(double)res/(double)nbrTry); + + + + // ******************** SCHEDULER ************************ + /* + res = 0; + startTime = System.currentTimeMillis(); + for (int i = 0; i < nbrTry; i++) { + res += findSolution2(nbrAgent, pr, maxGroup, localLimit, globalLimit); + // System.out.println("run : "+i); + } + estimatedTime = System.currentTimeMillis() - startTime; + + System.out.println("Time : "+estimatedTime/1000+ "s "+estimatedTime%1000+"ms"); + // System.out.println(res); + System.out.println("Average cycle : "+(double)res/(double)nbrTry); + */ + } + + private static int findSolution( + int nbrAgent, + double pr, + int maxGroup, + int localLimit, + int globalLimit + ) { + + // [INIT] + Eval eval = new StepFunction(); + //Eval eval = new SchwefelFunction1_2(); + //Eval eval = new SchwefelFunction(); + //Eval eval = new Rastrigin(); + + + + Env env = new Env(localLimit, globalLimit, maxGroup, eval); + + List<SMAgent> agents = new ArrayList<SMAgent>(); + for (int i = 0; i < nbrAgent; i++) { + agents.add(new SMAgent(i, pr, env, eval)); + } + + Group group = new Group(); + group.addAgents(agents); + env.initGroup(group); + + + // [RUN] + + int cycle = 0; + + while(Math.abs(eval.evaluate(env.getGlobalLeader())-eval.getObjective())>eval.getErrorDelta()) { + do { + for (SMAgent agent : agents) { + agent.perceive(); + } + for (SMAgent agent : agents) { + agent.decide(); + agent.act(); + + } + cycle++; + }while (agents.get(0).getPhase() != Phase.LOCAL_LEADER_PHASE); + //cycle ++; + //System.out.println("Cycle : "+cycle+" Value : "+eval.evaluate(env.getGlobalLeader())); + //System.out.println(env.getGlobalLeader()); + + /* + // Pas à Pas + try { + System.in.read(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + */ + + } + //System.out.println("Best solution : "+env.getGlobalLeader()); + //System.out.println("That evaluate to : "+eval.evaluate(env.getGlobalLeader())); + //System.out.println("Eval : "+eval.getCount()); + return cycle; + + } + + private static int findSolution2( + int nbrAgent, + double pr, + int maxGroup, + int localLimit, + int globalLimit) { + + // [INIT] + Eval eval = new StepFunction(); + //Eval eval = new SchwefelFunction1_2(); + //Eval eval = new SchwefelFunction(); + //Eval eval = new Rastrigin(); + + Env env = new Env(localLimit, globalLimit, maxGroup, eval); + + List<SMAgent> agents = new ArrayList<SMAgent>(); + for (int i = 0; i < nbrAgent; i++) { + agents.add(new SMAgent(i, pr, env, eval)); + } + + Group group = new Group(); + group.addAgents(agents); + env.initGroup(group); + + + // [RUN] + Scheduler scheduler = new Scheduler(env, eval, agents.toArray(new SMAgent[agents.size()])); + scheduler.start(); + + scheduler.waitUntilFinish(); + + return scheduler.getNbOfCycles(); + } + +} diff --git a/amakaque/Phase.java b/amakaque/Phase.java new file mode 100644 index 0000000..9900e31 --- /dev/null +++ b/amakaque/Phase.java @@ -0,0 +1,10 @@ +package amakaque; + +public enum Phase { + LOCAL_LEADER_PHASE, + GLOBAL_LEADER_PHASE, + GLOBAL_LEADER_LEARNING, + LOCAL_LEADER_LEARNING, + LOCAL_LEADER_DECISION, + GLOBAL_LEADER_DECISION, +} diff --git a/amakaque/SMAgent.java b/amakaque/SMAgent.java new file mode 100644 index 0000000..f77252e --- /dev/null +++ b/amakaque/SMAgent.java @@ -0,0 +1,442 @@ +package amakaque; + +import java.util.ArrayList; +import java.util.List; + +import eval.Eval; +import mas.core.Agent; + +public class SMAgent extends Agent { + + private Env env; + + /* + * Is local leader/ is global leader + * */ + private boolean isLL; + private boolean isGL; + + private int currentGroup; + private int id; + + private List<Double> dimVector; + private double fitness; + + private Double pr; + + private Phase phase; + + private Eval eval; + + // LLP + private List<Double> randomLocalMember; + private List<Double> localLeader; + + // GLP + // private List<Double> randomLocalMember; + private double maxFitness; + private List<Double> globalLeader; + private int groupSize; + private int count; + private boolean allDone; + + // GLL + private SMAgent nextGL; + private boolean isNewGL; + + //LLL + private SMAgent nextLL; + private boolean isNewLL; + + //LLD + // private List<Double> globalLeader; + // private List<Double> localLeader; + private int localLimit; + private int localLimitCount; + + //GLD + private int globalLimit; + private int globalLimitCount; + private int numberOfGroups; + private int numberOfGroupsLimit; + + /* + * Init the SM with random starting point within the env dimension + */ + public SMAgent(int _id, double _pr, Env _env, Eval _eval) { + env = _env; + eval = _eval; + id = _id; + if (id == 0) { + isLL = true; + isGL = true; + } + else { + isLL = false; + isGL = false; + } + currentGroup = 0; + + dimVector = new ArrayList<Double>(); + + for (int i = 0; i < eval.getDim(); i++) { + dimVector.add(eval.getMin(i) + Math.random() * (eval.getMax(i) - eval.getMin(i))); + } + + fitness = fitness(dimVector); + + pr = _pr; + phase = Phase.LOCAL_LEADER_PHASE; + } + + @Override + public void perceive() { + + + if (phase == Phase.LOCAL_LEADER_PHASE) { + + localLeader = env.getLocalLeader(currentGroup); + randomLocalMember = env.getRandomGroupMember(currentGroup, id); + } + else if(phase == Phase.GLOBAL_LEADER_PHASE){ + randomLocalMember = env.getRandomGroupMember(currentGroup, id); + globalLeader = env.getGlobalLeader(); + groupSize = env.getGroupSize(currentGroup); + maxFitness = env.getMaxFitness(); + count = env.getCount(currentGroup); + allDone = env.allDone(); + } + else if(phase == Phase.GLOBAL_LEADER_LEARNING) { + if (isGL) { + nextGL = env.findNextGL(); + } + this.isNewGL = false; + } + else if(phase == Phase.LOCAL_LEADER_LEARNING) { + if (isLL) { + nextLL = env.findNextLL(currentGroup); + } + isNewLL = false; + } + else if(phase == Phase.LOCAL_LEADER_DECISION) { + globalLeader = env.getGlobalLeader(); + localLeader = env.getLocalLeader(currentGroup); + localLimit = env.getLocalLimit(); + localLimitCount = env.getLocalLimitCount(currentGroup); + } + else if(phase == Phase.GLOBAL_LEADER_DECISION) { + if (localLimitCount > localLimit) { + if (isLL) { + env.resetLocalCount(currentGroup); + } + } + globalLimit = env.getGlobalLimit(); + globalLimitCount = env.getGlobalLimitCount(); + numberOfGroups = env.getNbrGroup(); + numberOfGroupsLimit = env.getGroupLimit(); + } + + } + + private double fitness(List<Double> values) { + double fun = eval.evaluate(values); + if (fun >= 0) { + return 1/(1 + fun); + } + else { + return 1 + Math.abs(fun); + } + } + + private void nextPhase() { + if (phase == Phase.LOCAL_LEADER_PHASE) { + phase = Phase.GLOBAL_LEADER_PHASE; + return; + } + else if(phase == Phase.GLOBAL_LEADER_PHASE){ + phase = Phase.GLOBAL_LEADER_LEARNING; + return; + } + else if(phase == Phase.GLOBAL_LEADER_LEARNING){ + phase = Phase.LOCAL_LEADER_LEARNING; + return; + } + else if(phase == Phase.LOCAL_LEADER_LEARNING){ + phase = Phase.LOCAL_LEADER_DECISION; + return; + } + else if(phase == Phase.LOCAL_LEADER_DECISION){ + phase = Phase.GLOBAL_LEADER_DECISION; + return; + } + else if(phase == Phase.GLOBAL_LEADER_DECISION){ + phase = Phase.LOCAL_LEADER_PHASE; + return; + } + } + + private void localLeaderPhase() { + /* + * For finding the objective (Food Source), + * generate the new positions for all the group members by using self experience, + * local leader experience and group members experience + */ + + List<Double> newValues = new ArrayList<Double>(); + + for (int i = 0; i < dimVector.size(); i++) { + + Double currentValue = dimVector.get(i); + + if (Math.random() >= pr) { + double value = currentValue + + Math.random() * (localLeader.get(i) - currentValue) + + 2 * (Math.random() - 0.5) * (randomLocalMember.get(i) - currentValue); + if (value > eval.getMax(i)) { + value = eval.getMax(i); + } + else if (value < eval.getMin(i)) { + value = eval.getMin(i); + } + newValues.add(value); + } + else { + newValues.add(currentValue); + } + } + + /* + * Apply the greedy selection process between existing position and newly generated position, + * based on fitness and select the better one; + */ + double new_fitness = fitness(newValues); + if (fitness<new_fitness) { + dimVector = newValues; + fitness = new_fitness; + } + } + + private void globalLeaderPhase() { + /* + * Calculate the probability prob for all the group members using equation + */ + double prob = 0.9 * fitness/maxFitness + 0.1; + + /* + * Produce new positions for the all the group members, selected by probi , + * by using self experience, global leader experience and group members experiences. + */ + + if (count < groupSize) { + if (Math.random() < prob) { + env.count(currentGroup); + int j = (int)(Math.random() * dimVector.size()); + + List<Double> newValues = new ArrayList<Double>(dimVector); + Double currentValue = dimVector.get(j); + double value = currentValue + + Math.random() * (globalLeader.get(j) - currentValue) + + (2*Math.random() - 1) * (randomLocalMember.get(j) - currentValue); + if (value > eval.getMax(j)) { + value = eval.getMax(j); + } + else if (value < eval.getMin(j)) { + value = eval.getMin(j); + } + newValues.set(j,value); + + + double new_fitness = fitness(newValues); + if (fitness<new_fitness) { + dimVector = newValues; + fitness = new_fitness; + } + } + } + } + + private void globalLeaderLearning() { + /* + * In this phase, the position of the global leader is updated by applying the greedy selection in the population i.e., + * the position of the SM having best fitness in the population is selected as the updated position of the global leader. + * Further, it is checked that the position of global leader is updating or not and if not then the GlobalLimitCount is incremented by 1. + */ + + if (isGL && ! this.isNewGL ) { + if (nextGL.equals(this)) { + env.addGlobalLimitCount(); + } + else { + nextGL.becomeGL(); + isGL = false; + } + } + } + + private void localLeaderLearning() { + /* + * In this phase, the position of the local leader is updated by applying the greedy selection in that group i.e., + * the position of the SM having best fitness in that group is selected as the updated position of the local leader. + * Next, the updated position of the local leader is compared with the old one + * and if the local leader is not updated then the LocalLimitCount is incremented by 1. + */ + if (isLL && ! this.isNewLL ) { + if (nextLL.equals(this)) { + env.addLocalLimit(currentGroup); + } + else { + nextLL.becomeLL(); + isLL = false; + } + } + } + + private void localLeaderDecision() { + + /* + * If any Local group leader is not updating her position after a specified number of times (LocalLeaderLimit) + * then re-direct all members of that particular group for foraging by algorithm + */ + if (localLimitCount > localLimit) { + List<Double> newValues = new ArrayList<Double>(); + + for (int j = 0; j < dimVector.size(); j++) { + + Double currentValue = dimVector.get(j); + + if (Math.random() >= pr) { + newValues.add(eval.getMin(j) + Math.random() * (eval.getMax(j) - eval.getMin(j))); + } + else { + newValues.add( + currentValue + + Math.random() * (globalLeader.get(j) - currentValue) + + Math.random() * (currentValue - localLeader.get(j)) + ); + } + } + + dimVector = newValues; + fitness = fitness(dimVector); + + } + } + + private void globalLeaderDecision() { + + /* + * If Global Leader is not updating her position for a specified number of times (GlobalLeaderLimit) + * then she divides the group into smaller groups by algorithm + */ + if (isGL) { + if (globalLimitCount > globalLimit) { + env.resetGlobalCount(); + + if (numberOfGroups < numberOfGroupsLimit) { + env.combineAllGroups(); + env.splitInNGroups(numberOfGroups+1); + + for (int i = 0; i < numberOfGroups+1; i++ ) { + env.findNextLL(i).becomeLL(); + } + + } + else { + env.combineAllGroups(); + env.findNextLL(0).becomeLL(); + } + + + } + } + + + } + + @Override + public void act() { + + if (phase == Phase.LOCAL_LEADER_PHASE) { + localLeaderPhase(); + nextPhase(); + + if (isLL) { // local leader reset his group count before next phase + env.resetGroupCount(currentGroup); + } + + } + else if(phase == Phase.GLOBAL_LEADER_PHASE){ + if (allDone) { + nextPhase(); + } + else { + globalLeaderPhase(); + } + } + else if(phase == Phase.GLOBAL_LEADER_LEARNING) { + globalLeaderLearning(); + nextPhase(); + } + else if(phase == Phase.LOCAL_LEADER_LEARNING) { + localLeaderLearning(); + nextPhase(); + } + else if(phase == Phase.LOCAL_LEADER_DECISION) { + localLeaderDecision(); + nextPhase(); + } + else if(phase == Phase.GLOBAL_LEADER_DECISION) { + globalLeaderDecision(); + nextPhase(); + } + } + + public List<Double> getDimVector() { + return dimVector; + } + + public int getId() { + return id; + } + + public boolean isLL() { + return isLL; + } + + public boolean isGL() { + return isGL; + } + + public void becomeGL() { + this.isGL = true; + this.isNewGL = true; + } + + public void becomeLL() { + isLL = true; + isNewLL = true; + } + + public void giveLocalLeadership() { + isLL = false; + } + + public void enterNewGroup(int group) { + currentGroup = group; + } + + public Phase getPhase() { + return phase; + } + + public double getFitness() { + return fitness; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SMAgent)) return false; + SMAgent SMobj = (SMAgent) obj; + return this.id == SMobj.id; + } +} diff --git a/amakaque/Scheduler.java b/amakaque/Scheduler.java new file mode 100644 index 0000000..bb0b501 --- /dev/null +++ b/amakaque/Scheduler.java @@ -0,0 +1,26 @@ +package amakaque; + +import eval.Eval; +import mas.core.ThreeStepCyclable; +import mas.implementation.schedulers.variations.ThreeStepCycling; + +public class Scheduler extends ThreeStepCycling{ + + public Env env; + public Eval eval; + + + public Scheduler(Env _env, Eval _eval, ThreeStepCyclable... _threeStepCyclables) { + super(_threeStepCyclables); + env = _env; + eval = _eval; + } + + @Override + public boolean stopCondition() { + if (env.getGroups().get(0).getAgents().get(0).getPhase() != Phase.LOCAL_LEADER_PHASE) { + return false; + } + return Math.abs(eval.evaluate(env.getGlobalLeader())-eval.getObjective())<=eval.getErrorDelta(); + } +} diff --git a/ant/Ant.java b/ant/Ant.java new file mode 100644 index 0000000..27643bb --- /dev/null +++ b/ant/Ant.java @@ -0,0 +1,169 @@ +package ant; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import eval.Eval; +import mas.core.Agent; + +public class Ant extends Agent{ + + private List<Double> vector; + double evaluate; + + Eval eval; + Env env; + + Phase phase; + int id; + + private double evaporationRate; + + // EVAL + + // BUILD NEW + private List<Solution> archive; + private List<Double> archiveProba; + + public Ant(int _id, Eval _eval, Env _env, double _evaporationRate) { + eval = _eval; + env = _env; + + evaporationRate = _evaporationRate; + + vector = new ArrayList<Double>(); + for (int i = 0; i < eval.getDim(); i++) { + vector.add(eval.getMin(i) + Math.random() * (eval.getMax(i) - eval.getMin(i))); + } + + evaluate = evaluate(vector); + + phase = Phase.EVALUATE; + + id = _id; + + } + + private double evaluate(List<Double> values) { + return eval.evaluate(values); + } + + private void nextPhase() { + if (phase == Phase.EVALUATE) { + phase = Phase.BUILD_NEW; + } + else if (phase == Phase.BUILD_NEW) { + phase = Phase.EVALUATE; + } + } + + @Override + public void perceive() { + /* + if(id == 0) { + System.out.println("\n\n"); + } + System.out.println(this); + */ + + + if (phase == Phase.EVALUATE) { + if(id == 0) { + + } + } + else if (phase == Phase.BUILD_NEW) { + archive = env.getArchive(); + archiveProba = env.getArchiveProba(); + if (id == 0) { + System.out.println(archive); + } + } + } + + @Override + public void act() { + if (phase == Phase.EVALUATE) { + if(id == 0) { + env.updateArchive(); + env.computeProba(); + } + } + else if (phase == Phase.BUILD_NEW) { + + vector = buildNewSolution(); + evaluate = evaluate(vector); + + } + nextPhase(); + } + + public int chooseSolution() { + double prob = Math.random(); + + double res = archiveProba.get(0); + int i = 0; + while (res<prob) { + i ++; + res += archiveProba.get(i); + } + return i; + } + + public List<Double> buildNewSolution(){ + + int archiveLen = archive.size(); + + Random ran = new Random(); + + List<Double> sol = new ArrayList<Double>(); + + + for (int j = 0; j < eval.getDim(); j++) { + int i_archive = chooseSolution(); + List<Double> init = archive.get(i_archive).getVector(); + + double d = 0; + for(int i = 0; i < archiveLen; i++) { + d += Math.abs(archive.get(i).getVector().get(j) - init.get(j))/(archiveLen-1); + } + + double o = evaporationRate * d; + + double possibleSol = ran.nextGaussian(init.get(j), o); + + if (possibleSol > eval.getMax(j)) { + possibleSol = eval.getMax(j); + } + else if (possibleSol < eval.getMin(j)) { + possibleSol = eval.getMin(j); + } + + sol.add(possibleSol); + } + + return sol; + } + + public List<Double> getVector() { + return vector; + } + + public double getEvaluate() { + return evaluate; + } + + public Phase getPhase() { + return phase; + } + + @Override + public String toString() { + return + "[AGENT] " + id + "\n" + + " - Phase " + phase + "\n" + + " - Eval " + evaluate + "\n" + + " - Vector" + vector + "\n"; + } +} diff --git a/ant/Env.java b/ant/Env.java new file mode 100644 index 0000000..4c7a7f3 --- /dev/null +++ b/ant/Env.java @@ -0,0 +1,106 @@ +package ant; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Random; + +import eval.Eval; + +public class Env { + + private List<Solution> archive; + private List<Double> archiveProba; + + private Eval eval; + + private List<Ant> agents; + + private int archiveLen; + private double q; + + public Env(int _archiveLen, double _q, Eval _eval) { + archiveLen = _archiveLen; + q = _q; + + archive = new ArrayList<Solution>(); + archiveProba = new ArrayList<Double>(); + + eval = _eval; + } + + public void initAgents(List<Ant> _agents) { + agents = new ArrayList<Ant>(_agents); + updateArchive(); + } + + private void sortArchive() { + Collections.sort(archive, new Comparator<Solution>() { + @Override + public int compare(Solution o1, Solution o2) { + if (o1.getEval() > o2.getEval()) { + return 1; + } + if (o1.getEval() < o2.getEval()) { + return -1; + } + return 0; + } + }); + } + + private void sortAndRemoveSolution() { + sortArchive(); + + while(archive.size() > archiveLen) { + archive.remove(archive.size()-1); + } + } + + public void updateArchive() { + for (Ant agent: agents) { + archive.add(new Solution(agent.getVector(), agent.getEvaluate())); + } + + sortAndRemoveSolution(); + } + + public void computeProba() { + archiveProba = new ArrayList<Double>(); + + List<Double> w = new ArrayList<Double>(); + double wMax = 0; + + for(int i = 0; i < archiveLen; i++) { + double wi = 1/(q * archiveLen * Math.sqrt(2 * Math.PI)) + * Math.exp(-Math.pow(i,2) / (2 * Math.pow(q, 2) * Math.pow(archiveLen, 2))); + w.add(wi); + wMax += wi; + } + + for(int i = 0; i < archiveLen; i++) { + archiveProba.add(w.get(i)/wMax); + } + } + + public List<Solution> getArchive() { + return archive; + } + + public List<Double> getArchiveProba() { + return archiveProba; + } + + public Eval getEval() { + return eval; + } + + public List<Ant> getAgents() { + return agents; + } + + public double bestValue() { + return archive.get(archive.size()-1).getEval(); + } +} diff --git a/ant/MainAnt.java b/ant/MainAnt.java new file mode 100644 index 0000000..ced49a5 --- /dev/null +++ b/ant/MainAnt.java @@ -0,0 +1,119 @@ +package ant; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import eval.Eval; +import eval.fun.SchwefelFunction; +import eval.fun.SchwefelFunction1_2; +import eval.fun.StepFunction; + +/* + * https://www.sciencedirect.com/science/article/pii/S0952197619301940#fig1 + * https://towardsdatascience.com/introduction-to-global-optimization-algorithms-for-continuous-domain-functions-7ad9d01db055 + */ + +public class MainAnt { + public static void main(String[] args) { + // [PARAM] + + int nbrAgent = 40; + int archiveSize = 10; + + double evaporation = 0.6; + double q = 0.2; + + int res = 0; + int nbrTry = 1; + + long startTime = System.currentTimeMillis(); + for (int i = 0; i < nbrTry; i++) { + // [INIT] + //Eval eval = new StepFunction(); + Eval eval = new SchwefelFunction1_2(); + //Eval eval = new SchwefelFunction(); + //Eval eval = new Rastrigin(); + + + Env env = new Env(archiveSize, q, eval); + + List<Ant> agents = new ArrayList<Ant>(); + for (int i_agent = 0; i_agent < nbrAgent; i_agent++) { + agents.add(new Ant(i_agent, eval, env, evaporation)); + } + + env.initAgents(agents); + + res += findSolution(nbrAgent, env, eval, agents); + System.out.println("run : "+i); + System.out.println("Nbr eval :"+eval.getCount()); + } + long estimatedTime = System.currentTimeMillis() - startTime; + + System.out.println("Time : "+estimatedTime/1000+ "s "+estimatedTime%1000+"ms"); + System.out.println(res); + System.out.println("Average cycle : "+(double)res/(double)nbrTry); + + } + + private static int findSolution( + int nbrAgent, + Env env, + Eval eval, + List<Ant> agents + ) { + + // [RUN] + + int cycle = 0; + + do { + do { + for (Ant agent : agents) { + agent.perceive(); + } + for (Ant agent : agents) { + agent.decide(); + agent.act(); + + } + cycle++; + }while (agents.get(0).getPhase() != Phase.EVALUATE); + cycle ++; + System.out.println("Cycle : "+cycle+" Value : "+env.bestValue()); + + /* + // Pas à Pas + try { + System.in.read(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + */ + + + } while(Math.abs(env.bestValue()-eval.getObjective())>eval.getErrorDelta()); + + return cycle; + + } + + private static int findSolution2( + int nbrAgent, + Env env, + Eval eval, + List<Ant> agents + ) { + + // [RUN] + Scheduler scheduler = new Scheduler(env, eval, agents.toArray(new Ant[agents.size()])); + scheduler.start(); + + scheduler.waitUntilFinish(); + + return scheduler.getNbOfCycles(); + } + +} \ No newline at end of file diff --git a/ant/Phase.java b/ant/Phase.java new file mode 100644 index 0000000..d6d7026 --- /dev/null +++ b/ant/Phase.java @@ -0,0 +1,6 @@ +package ant; + +public enum Phase { + BUILD_NEW, + EVALUATE +} diff --git a/ant/Scheduler.java b/ant/Scheduler.java new file mode 100644 index 0000000..327ce49 --- /dev/null +++ b/ant/Scheduler.java @@ -0,0 +1,28 @@ +package ant; + +import java.util.List; + +import eval.Eval; +import mas.core.ThreeStepCyclable; +import mas.implementation.schedulers.variations.ThreeStepCycling; + +public class Scheduler extends ThreeStepCycling{ + + public Env env; + public Eval eval; + + + public Scheduler(Env _env, Eval _eval, ThreeStepCyclable... _threeStepCyclables) { + super(_threeStepCyclables); + env = _env; + eval = _eval; + } + + @Override + public boolean stopCondition() { + if (env.getAgents().get(0).getPhase() != Phase.EVALUATE) { + return false; + } + return Math.abs(env.bestValue()-eval.getObjective())<=eval.getErrorDelta(); + } +} \ No newline at end of file diff --git a/ant/Solution.java b/ant/Solution.java new file mode 100644 index 0000000..1142fb1 --- /dev/null +++ b/ant/Solution.java @@ -0,0 +1,27 @@ +package ant; + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + private List<Double> vector; + private double eval; + + public Solution(List<Double> _vector, double _eval) { + eval = _eval; + vector = new ArrayList<Double>(_vector); + } + + public double getEval() { + return eval; + } + + public List<Double> getVector() { + return vector; + } + + @Override + public String toString() { + return ""+eval; + } +} diff --git a/baseOptiAgent/BaseAgent.java b/baseOptiAgent/BaseAgent.java new file mode 100644 index 0000000..b02310b --- /dev/null +++ b/baseOptiAgent/BaseAgent.java @@ -0,0 +1,53 @@ +package baseOptiAgent; + +import java.util.ArrayList; +import java.util.List; + +import eval.Eval; +import mas.core.Agent; + +public abstract class BaseAgent extends Agent{ + + private List<Double> vector; + private double fitness; + private double evaluate; + + private Eval eval; + + private int id; + + private void boundValue(List<Double> vector) { + for(int i = 0; i < vector.size(); i++) { + if (vector.get(i) > eval.getMax(i)) { + vector.set(i, eval.getMax(i)); + } + else if (vector.get(i) > eval.getMax(i)) { + vector.set(i, eval.getMin(i)); + } + } + } + + private List<Double> generateRandomVector(){ + List<Double> result = new ArrayList<Double>(); + + for (int i = 0; i < eval.getDim(); i++) { + result.add(eval.getMin(i) + Math.random() * (eval.getMax(i) - eval.getMin(i))); + } + boundValue(result); + return result; + } + + private double evaluate(List<Double> vector) { + return eval.evaluate(vector); + } + + private double fitness(double value) { + if (value >= 0) { + return 1/(1 + value); + } + else { + return 1 + Math.abs(value); + } + } + +} diff --git a/eval/Eval.java b/eval/Eval.java new file mode 100644 index 0000000..d775864 --- /dev/null +++ b/eval/Eval.java @@ -0,0 +1,41 @@ +package eval; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public abstract class Eval { + + protected double objective; + protected int dim; + protected List<Double> min; + protected List<Double> max; + protected double errorDelta; + + protected AtomicInteger count; + + public abstract double evaluate(List<Double> value); + + public Double getMin(int i) { + return min.get(i); + } + + public Double getMax(int i) { + return max.get(i); + } + + public double getErrorDelta() { + return errorDelta; + } + + public double getObjective() { + return objective; + } + + public int getDim() { + return dim; + } + + public int getCount() { + return count.intValue(); + } +} diff --git a/eval/fun/Levy_function_1.java b/eval/fun/Levy_function_1.java new file mode 100644 index 0000000..948e294 --- /dev/null +++ b/eval/fun/Levy_function_1.java @@ -0,0 +1,36 @@ +package eval.fun; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import eval.Eval; + +public class Levy_function_1 extends Eval{ + + public Levy_function_1() { + count = new AtomicInteger(0); + + dim = 30; + objective = (double) 0; + errorDelta = 0.001; + + min = new ArrayList<Double>(); + max = new ArrayList<Double>(); + for (int i = 0; i < dim; i++) { + min.add((double) -50); + max.add((double) 50); + } + } + + @Override + public double evaluate(List<Double> value) { + count.getAndIncrement(); + double result = 0; + + //TODO + + return result; + } + +} diff --git a/eval/fun/Rastrigin.java b/eval/fun/Rastrigin.java new file mode 100644 index 0000000..6fde05c --- /dev/null +++ b/eval/fun/Rastrigin.java @@ -0,0 +1,39 @@ +package eval.fun; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import eval.Eval; + +public class Rastrigin extends Eval{ + + public Rastrigin() { + count = new AtomicInteger(0); + + dim = 30; + objective = (double) 0; + errorDelta = 0.001; + + min = new ArrayList<Double>(); + max = new ArrayList<Double>(); + for (int i = 0; i < dim; i++) { + min.add((double) -5.12); + max.add((double) 5.12); + } + } + + @Override + public double evaluate(List<Double> value) { + count.getAndIncrement(); + double result = 10*dim; + + for(int i_dim = 0; i_dim < dim; i_dim++ ) { + result += (value.get(i_dim) * value.get(i_dim) - 10 * Math.cos(2 * Math.PI * value.get(i_dim))); + } + + return result; + } + + +} \ No newline at end of file diff --git a/eval/fun/SchwefelFunction.java b/eval/fun/SchwefelFunction.java new file mode 100644 index 0000000..739e296 --- /dev/null +++ b/eval/fun/SchwefelFunction.java @@ -0,0 +1,39 @@ +package eval.fun; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import eval.Eval; + +public class SchwefelFunction extends Eval{ + + public SchwefelFunction() { + count = new AtomicInteger(0); + + dim = 30; + objective = (double) -418.9829* dim; + errorDelta = 0.001; + + min = new ArrayList<Double>(); + max = new ArrayList<Double>(); + for (int i = 0; i < dim; i++) { + min.add((double) -500); + max.add((double) 500); + } + } + + @Override + public double evaluate(List<Double> value) { + count.getAndIncrement(); + double result = 0; + + for(int i_dim = 0; i_dim < dim; i_dim++ ) { + result += (value.get(i_dim) * Math.sin(Math.sqrt(Math.abs(value.get(i_dim))))); + } + + return result; + } + + +} diff --git a/eval/fun/SchwefelFunction1_2.java b/eval/fun/SchwefelFunction1_2.java new file mode 100644 index 0000000..b4a3fec --- /dev/null +++ b/eval/fun/SchwefelFunction1_2.java @@ -0,0 +1,44 @@ +package eval.fun; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import eval.Eval; + +public class SchwefelFunction1_2 extends Eval{ + + + public SchwefelFunction1_2() { + count = new AtomicInteger(0); + + dim = 30; + objective = (double) 0; + errorDelta = 0.001; + + min = new ArrayList<Double>(); + max = new ArrayList<Double>(); + for (int i = 0; i < dim; i++) { + min.add((double) -100); + max.add((double) 100); + } + } + + @Override + public double evaluate(List<Double> value) { + count.getAndIncrement(); + double result = 0; + + for(int i_dim = 0; i_dim < dim; i_dim++ ) { + double tmp_res = 0; + for(int j_dim = 0; j_dim < i_dim; j_dim++ ) { + tmp_res += value.get(j_dim); + } + result += tmp_res*tmp_res; + } + + return result; + } + + +} diff --git a/eval/fun/StepFunction.java b/eval/fun/StepFunction.java new file mode 100644 index 0000000..91e30e7 --- /dev/null +++ b/eval/fun/StepFunction.java @@ -0,0 +1,38 @@ +package eval.fun; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import eval.Eval; + +public class StepFunction extends Eval{ + + public StepFunction() { + count = new AtomicInteger(0); + + dim = 30; + objective = (double) 0; + errorDelta = 0.01; + + min = new ArrayList<Double>(); + max = new ArrayList<Double>(); + for (int i = 0; i < dim; i++) { + min.add((double) -100); + max.add((double) 100); + } + } + + @Override + public double evaluate(List<Double> value) { + count.getAndIncrement(); + double result = 0; + + for(int i_dim = 0; i_dim < dim; i_dim++ ) { + result += Math.pow(Math.floor(0.5+value.get(i_dim)), 2); + } + return result; + } + + +} -- GitLab