View Javadoc
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 }