1 package net.bmahe.genetics4j.gpu.spec;
2
3 import java.util.Arrays;
4 import java.util.Collection;
5 import java.util.Objects;
6 import java.util.function.Predicate;
7
8 import org.apache.commons.lang3.Validate;
9
10 import net.bmahe.genetics4j.gpu.opencl.model.Device;
11 import net.bmahe.genetics4j.gpu.opencl.model.DeviceType;
12
13 /**
14 * Utility class providing predicate-based filters for selecting OpenCL devices in GPU-accelerated evolutionary
15 * algorithms.
16 *
17 * <p>DeviceFilters offers a fluent API for creating device selection criteria based on device characteristics such as
18 * type, capabilities, and performance metrics. These filters are used to automatically select appropriate OpenCL
19 * devices for GPU-accelerated evolutionary algorithm execution.
20 *
21 * <p>Key functionality includes:
22 * <ul>
23 * <li><strong>Type-based filtering</strong>: Select devices by type (GPU, CPU, accelerator)</li>
24 * <li><strong>Logical combinations</strong>: Combine filters using AND and OR operations</li>
25 * <li><strong>Performance filtering</strong>: Filter devices based on computational capabilities</li>
26 * <li><strong>Predicate composition</strong>: Build complex selection criteria from simple predicates</li>
27 * </ul>
28 *
29 * <p>Common usage patterns:
30 *
31 * <pre>{@code
32 * // Select GPU devices only
33 * Predicate<Device> gpuFilter = DeviceFilters.ofGPU();
34 *
35 * // Select CPU devices only
36 * Predicate<Device> cpuFilter = DeviceFilters.ofCPU();
37 *
38 * // Select GPU or accelerator devices
39 * Predicate<Device> computeFilter = DeviceFilters
40 * .or(DeviceFilters.ofGPU(), DeviceFilters.ofType(DeviceType.ACCELERATOR));
41 *
42 * // Select high-performance GPU devices
43 * Predicate<Device> highPerformanceGPU = DeviceFilters.and(
44 * DeviceFilters.ofGPU(),
45 * device -> device.maxComputeUnits() >= 8,
46 * device -> device.maxWorkGroupSize() >= 256);
47 *
48 * // Apply filter to device selection
49 * GPUEAExecutionContext context = GPUEAExecutionContext.builder().deviceFilters(gpuFilter).build();
50 * }</pre>
51 *
52 * <p>Device selection workflow:
53 * <ol>
54 * <li><strong>Platform discovery</strong>: Enumerate available OpenCL platforms</li>
55 * <li><strong>Device enumeration</strong>: Discover devices on selected platforms</li>
56 * <li><strong>Filter application</strong>: Apply device filters to candidate devices</li>
57 * <li><strong>Device selection</strong>: Select filtered devices for EA execution</li>
58 * </ol>
59 *
60 * <p>Filter composition patterns:
61 * <ul>
62 * <li><strong>Type filtering</strong>: Select devices by computational type</li>
63 * <li><strong>Capability filtering</strong>: Filter by device computational capabilities</li>
64 * <li><strong>Performance filtering</strong>: Select devices meeting performance criteria</li>
65 * <li><strong>Logical combinations</strong>: Combine multiple criteria using boolean logic</li>
66 * </ul>
67 *
68 * <p>Performance considerations:
69 * <ul>
70 * <li><strong>Device enumeration overhead</strong>: Filters are applied during device discovery</li>
71 * <li><strong>Capability validation</strong>: Ensure selected devices meet algorithm requirements</li>
72 * <li><strong>Load balancing</strong>: Consider device performance when selecting multiple devices</li>
73 * <li><strong>Fallback strategies</strong>: Implement fallback filters for systems with limited devices</li>
74 * </ul>
75 *
76 * @see Device
77 * @see DeviceType
78 * @see GPUEAExecutionContext
79 */
80 public class DeviceFilters {
81
82 private DeviceFilters() {
83
84 }
85
86 /**
87 * Creates a predicate that filters devices by the specified device type.
88 *
89 * @param deviceType the OpenCL device type to filter for
90 * @return predicate that returns true for devices of the specified type
91 * @throws IllegalArgumentException if deviceType is null
92 */
93 public static Predicate<Device> ofType(final DeviceType deviceType) {
94 Objects.requireNonNull(deviceType);
95
96 return device -> device.deviceType().contains(deviceType);
97 }
98
99 /**
100 * Creates a predicate that filters for GPU devices only.
101 *
102 * <p>This is a convenience method equivalent to {@code ofType(DeviceType.GPU)}.
103 *
104 * @return predicate that returns true for GPU devices
105 */
106 public static Predicate<Device> ofGPU() {
107 return ofType(DeviceType.GPU);
108 }
109
110 /**
111 * Creates a predicate that filters for CPU devices only.
112 *
113 * <p>This is a convenience method equivalent to {@code ofType(DeviceType.CPU)}.
114 *
115 * @return predicate that returns true for CPU devices
116 */
117 public static Predicate<Device> ofCPU() {
118 return ofType(DeviceType.CPU);
119 }
120
121 /**
122 * Creates a predicate that returns true if any of the provided predicates return true (logical OR).
123 *
124 * @param predicates array of device predicates to combine with OR logic
125 * @return predicate that returns true if any input predicate returns true
126 * @throws IllegalArgumentException if predicates is null or empty
127 */
128 public static Predicate<Device> or(@SuppressWarnings("unchecked") final Predicate<Device>... predicates) {
129 Objects.requireNonNull(predicates);
130 Validate.isTrue(predicates.length > 0);
131
132 return device -> Arrays.stream(predicates).anyMatch(predicate -> predicate.test(device));
133 }
134
135 /**
136 * Creates a predicate that returns true if any of the provided predicates return true (logical OR).
137 *
138 * @param predicates collection of device predicates to combine with OR logic
139 * @return predicate that returns true if any input predicate returns true
140 * @throws IllegalArgumentException if predicates is null or empty
141 */
142 public static Predicate<Device> or(final Collection<Predicate<Device>> predicates) {
143 Objects.requireNonNull(predicates);
144 Validate.isTrue(predicates.isEmpty() == false);
145
146 return device -> predicates.stream().anyMatch(predicate -> predicate.test(device));
147 }
148
149 /**
150 * Creates a predicate that returns true only if all provided predicates return true (logical AND).
151 *
152 * @param predicates array of device predicates to combine with AND logic
153 * @return predicate that returns true only if all input predicates return true
154 * @throws IllegalArgumentException if predicates is null or empty
155 */
156 @SafeVarargs
157 public static Predicate<Device> and(final Predicate<Device>... predicates) {
158 Objects.requireNonNull(predicates);
159 Validate.isTrue(predicates.length > 0);
160
161 return device -> Arrays.stream(predicates).allMatch(predicate -> predicate.test(device));
162 }
163
164 /**
165 * Creates a predicate that returns true only if all provided predicates return true (logical AND).
166 *
167 * @param predicates collection of device predicates to combine with AND logic
168 * @return predicate that returns true only if all input predicates return true
169 * @throws IllegalArgumentException if predicates is null or empty
170 */
171 public static Predicate<Device> and(final Collection<Predicate<Device>> predicates) {
172 Objects.requireNonNull(predicates);
173 Validate.isTrue(predicates.isEmpty() == false);
174
175 return device -> predicates.stream().allMatch(predicate -> predicate.test(device));
176 }
177
178 }