{"id":1458,"date":"2021-05-13T12:46:48","date_gmt":"2021-05-13T10:46:48","guid":{"rendered":"https:\/\/craftcoders.app\/?p=1458"},"modified":"2024-08-14T14:27:51","modified_gmt":"2024-08-14T12:27:51","slug":"solving-the-knapsack-problem-with-the-jenetics-library","status":"publish","type":"post","link":"https:\/\/craftcoders.app\/solving-the-knapsack-problem-with-the-jenetics-library\/","title":{"rendered":"Solving the Knapsack Problem with the Jenetics Library"},"content":{"rendered":"\r\n
According to its official documents<\/a>, Jenetics is a library that is used for programming evolutionary algorithms written in Java. Jenetics is implemented using the Java Stream<\/em> interface, so it works smoothly with the rest of the Java Stream<\/em> API. Evolutionary algorithms have their roots in biology, as they use mechanisms inspired by biological evolution, such as reproduction, mutation, recombination, and selection. If you want to learn more about the theory behind evolutionary algorithms, I’d suggest reading Introduction to Evolutionary Algorithms<\/a> first.<\/p>\r\n\r\n\r\n\r\n Disclaimer:<\/strong> This blog post is based on Introduction to Jenetics Library<\/a> from Baeldung. But it is using the current library version (6.2.0) and a more complex example: The knapsack problem without using the libraries provided classes for the problem.<\/p>\r\n\r\n\r\n\r\n Given a set of items, each with a weight and a value, determine the number of each item to include in a collection so that the total weight is less than or equal to a given limit and the total value is as large as possible. It derives its name from the problem faced by someone who is constrained by a fixed-size knapsack<\/a> and must fill it with the most valuable items.<\/p>\r\nWikipedia<\/a><\/cite><\/blockquote>\r\n\r\n\r\n\r\n\r\n\r\n In the following example, we have a class called “Knapsack” that represents our problem. The class defines items that consist of a size and a value (possibleKnapsackItems<\/strong>). These items are initialized with random values between 0 and 10 and put in a list to represent the items we can put into our knapsack. Furthermore, the class defines the maximum size the knapsack can hold. Attention: Don’t mix up the size of the knapsack (Knapsack.getKnapsackSize<\/strong>) with the number of items that we could<\/em> put in the knapsack (Knapsack.getItemCount<\/strong>). The items that we actually put into the knapsack will be defined later in our evolutionary algorithm.<\/p>\r\n\r\n\r\n\r\n In order to use Jenetics, we need to add the following dependency into our build.gradle<\/em>:<\/p>\r\n\r\n\r\n\r\n Next we create a runnable class App<\/strong> that will use the Jenetics library and our Knapsack class to run a genetic algorithm. First, let’s make use of our previously created class: We create a knapsack with a size of 100 and 80 items from which we can pick.<\/p>\r\n\r\n\r\n\r\n Let’s work on the run()<\/strong> function. We need to convert the Knapsack problem into another representation that a genetic algorithm can work with, namely a chromosome. And indeed we can transform it into a so-called binary problem, where each one represents an item we put into the knapsack, each zero represents an item we don’t put in the knapsack.<\/p>\r\n\r\n\r\n\r\nThe knapsack problem<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n
\r\n
Defining the problem in code<\/h2>\r\n\r\n\r\n\r\n
public final class <\/strong>Knapsack {\r\n private final <\/strong>List<Item> possibleKnapsackItems<\/strong>; \/\/ items that *might* end up in the knapsack, depending on chromosome\r\n <\/em>private int knapsackSize<\/strong>;\r\n\r\n public <\/strong>Knapsack(List<Item> possibleItems, int <\/strong>knapsackSize) {\r\n this<\/strong>.possibleKnapsackItems <\/strong>= possibleItems;\r\n this<\/strong>.knapsackSize <\/strong>= knapsackSize;\r\n }\r\n\r\n public static <\/strong>Knapsack initializeWithRandomItems(int <\/strong>size, int <\/strong>knapsackSize) {\r\n Random random = new <\/strong>Random(123);\r\n List<Item> items = Stream.generate<\/em>(() -> \r\n new <\/strong>Item((int<\/strong>) (random.nextDouble()*10),(int<\/strong>) (random.nextDouble()*10)))\r\n .limit(size)\r\n .collect(Collectors.toList<\/em>());\r\n return new <\/strong>Knapsack(items, knapsackSize);\r\n }\r\n\r\n public <\/strong>Item getItemByIndex(int <\/strong>index) { return this<\/strong>.possibleKnapsackItems<\/strong>.get(index); }\r\n public int <\/strong>getItemCount() { return this<\/strong>.possibleKnapsackItems<\/strong>.size(); }\r\n public int <\/strong>getKnapsackSize() { return this<\/strong>.knapsackSize<\/strong>; }\r\n\r\n public static final class <\/strong>Item {\r\n private final int size<\/strong>;\r\n private final int value<\/strong>;\r\n\r\n public <\/strong>Item(final int <\/strong>size, final int <\/strong>value) {\r\n this<\/strong>.size <\/strong>= Requires.nonNegative<\/em>(size);\r\n this<\/strong>.value <\/strong>= Requires.nonNegative<\/em>(value);\r\n }\r\n\r\n public int <\/strong>getSize() { return size<\/strong>; }\r\n public int <\/strong>getValue() { return value<\/strong>; }\r\n }\r\n}<\/code><\/pre>\r\n\r\n\r\n\r\n\r\n\r\n
Let’s get started with the Jenetics Library<\/h2>\r\n\r\n\r\n\r\n
implementation 'io.jenetics:jenetics:6.2.0'<\/strong><\/code><\/pre>\r\n\r\n\r\n\r\n
public class <\/strong>App {\r\n private final static int ITEM_COUNT <\/em><\/strong>= 80;\r\n private final static int KNAPSACK_SIZE <\/em><\/strong>= 100;\r\n private final static int POPULATION_SIZE <\/em><\/strong>= 500;\r\n\r\n private final<\/strong> Knapsack knapsack <\/strong>= Knapsack.initializeWithRandomItems<\/em>(ITEM_COUNT<\/em><\/strong>, KNAPSACK_SIZE<\/em><\/strong>);\r\n\r\n public static void <\/strong>main(String[] args) {\r\n new <\/strong>App().run(POPULATION_SIZE<\/em><\/strong>);\r\n }\r\n\r\n public void <\/strong>run(int <\/strong>populationSize) {\r\n \/\/ TODO Run the genetic algorithm\r\n }\r\n}<\/code><\/pre>\r\n\r\n\r\n\r\n