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.Set;
7   import java.util.function.Predicate;
8   
9   import org.apache.commons.collections4.CollectionUtils;
10  import org.apache.commons.lang3.Validate;
11  
12  import net.bmahe.genetics4j.gpu.opencl.model.Platform;
13  import net.bmahe.genetics4j.gpu.opencl.model.PlatformProfile;
14  
15  /**
16   * Utility class providing predicate-based filters for selecting OpenCL platforms in GPU-accelerated evolutionary
17   * algorithms.
18   * 
19   * <p>PlatformFilters offers a fluent API for creating platform selection criteria based on platform characteristics
20   * such as profile type, supported extensions, and vendor capabilities. These filters are used to automatically select
21   * appropriate OpenCL platforms before device enumeration and selection.
22   * 
23   * <p>Key functionality includes:
24   * <ul>
25   * <li><strong>Profile-based filtering</strong>: Select platforms by profile (FULL_PROFILE or EMBEDDED_PROFILE)</li>
26   * <li><strong>Extension filtering</strong>: Filter platforms based on supported OpenCL extensions</li>
27   * <li><strong>Logical combinations</strong>: Combine filters using AND and OR operations</li>
28   * <li><strong>Predicate composition</strong>: Build complex selection criteria from simple predicates</li>
29   * </ul>
30   * 
31   * <p>Common usage patterns:
32   * 
33   * <pre>{@code
34   * // Select platforms with full OpenCL profile
35   * Predicate<Platform> fullProfileFilter = PlatformFilters.ofProfile(PlatformProfile.FULL_PROFILE);
36   * 
37   * // Select platforms supporting double precision arithmetic
38   * Predicate<Platform> fp64Filter = PlatformFilters.ofExtension("cl_khr_fp64");
39   * 
40   * // Select platforms with multiple required extensions
41   * Set<String> requiredExtensions = Set.of("cl_khr_fp64", "cl_khr_global_int32_base_atomics");
42   * Predicate<Platform> extensionFilter = PlatformFilters.ofExtensions(requiredExtensions);
43   * 
44   * // Combine multiple criteria
45   * Predicate<Platform> advancedFilter = PlatformFilters
46   * 		.and(PlatformFilters.ofProfile(PlatformProfile.FULL_PROFILE), PlatformFilters.ofExtension("cl_khr_fp64"));
47   * 
48   * // Apply filter to platform selection
49   * GPUEAExecutionContext context = GPUEAExecutionContext.builder().platformFilters(fullProfileFilter).build();
50   * }</pre>
51   * 
52   * <p>Platform selection workflow:
53   * <ol>
54   * <li><strong>Platform enumeration</strong>: Discover all available OpenCL platforms</li>
55   * <li><strong>Filter application</strong>: Apply platform filters to candidate platforms</li>
56   * <li><strong>Platform validation</strong>: Validate filtered platforms meet requirements</li>
57   * <li><strong>Device discovery</strong>: Enumerate devices on selected platforms</li>
58   * </ol>
59   * 
60   * <p>Filter criteria considerations:
61   * <ul>
62   * <li><strong>Profile compatibility</strong>: FULL_PROFILE platforms typically offer more features</li>
63   * <li><strong>Extension requirements</strong>: Filter for extensions required by algorithms</li>
64   * <li><strong>Vendor optimization</strong>: Consider vendor-specific optimizations and extensions</li>
65   * <li><strong>Version requirements</strong>: Ensure platforms support required OpenCL versions</li>
66   * </ul>
67   * 
68   * <p>Performance considerations:
69   * <ul>
70   * <li><strong>Platform enumeration overhead</strong>: Filters are applied during platform discovery</li>
71   * <li><strong>Extension validation</strong>: Extension checks may have runtime overhead</li>
72   * <li><strong>Fallback strategies</strong>: Implement fallback filters for limited platform availability</li>
73   * <li><strong>Caching</strong>: Platform characteristics are typically static during execution</li>
74   * </ul>
75   * 
76   * @see Platform
77   * @see PlatformProfile
78   * @see GPUEAExecutionContext
79   */
80  public class PlatformFilters {
81  
82  	private PlatformFilters() {
83  
84  	}
85  
86  	/**
87  	 * Creates a predicate that filters platforms by the specified profile type.
88  	 * 
89  	 * @param platformProfile the OpenCL profile type to filter for (FULL_PROFILE or EMBEDDED_PROFILE)
90  	 * @return predicate that returns true for platforms with the specified profile
91  	 * @throws IllegalArgumentException if platformProfile is null
92  	 */
93  	public static Predicate<Platform> ofProfile(final PlatformProfile platformProfile) {
94  		Objects.requireNonNull(platformProfile);
95  
96  		return platform -> platformProfile.equals(platform.profile());
97  	}
98  
99  	/**
100 	 * Creates a predicate that filters platforms supporting the specified OpenCL extension.
101 	 * 
102 	 * @param extension the OpenCL extension name to filter for (e.g., "cl_khr_fp64")
103 	 * @return predicate that returns true for platforms supporting the extension
104 	 * @throws IllegalArgumentException if extension is null or blank
105 	 */
106 	public static Predicate<Platform> ofExtension(final String extension) {
107 		Validate.notBlank(extension);
108 
109 		return platform -> platform.extensions().contains(extension);
110 	}
111 
112 	/**
113 	 * Creates a predicate that filters platforms supporting all specified OpenCL extensions.
114 	 * 
115 	 * @param extensions set of OpenCL extension names that must all be supported
116 	 * @return predicate that returns true for platforms supporting all specified extensions
117 	 * @throws IllegalArgumentException if extensions is null
118 	 */
119 	public static Predicate<Platform> ofExtensions(final Set<String> extensions) {
120 		Objects.requireNonNull(extensions);
121 
122 		return platform -> CollectionUtils.containsAll(platform.extensions(), extensions);
123 	}
124 
125 	/**
126 	 * Creates a predicate that returns true if any of the provided predicates return true (logical OR).
127 	 * 
128 	 * @param predicates array of platform predicates to combine with OR logic
129 	 * @return predicate that returns true if any input predicate returns true
130 	 * @throws IllegalArgumentException if predicates is null or empty
131 	 */
132 	public static Predicate<Platform> or(@SuppressWarnings("unchecked") final Predicate<Platform>... predicates) {
133 		Objects.requireNonNull(predicates);
134 		Validate.isTrue(predicates.length > 0);
135 
136 		return platform -> Arrays.stream(predicates).anyMatch(predicate -> predicate.test(platform));
137 	}
138 
139 	/**
140 	 * Creates a predicate that returns true if any of the provided predicates return true (logical OR).
141 	 * 
142 	 * @param predicates collection of platform predicates to combine with OR logic
143 	 * @return predicate that returns true if any input predicate returns true
144 	 * @throws IllegalArgumentException if predicates is null or empty
145 	 */
146 	public static Predicate<Platform> or(final Collection<Predicate<Platform>> predicates) {
147 		Objects.requireNonNull(predicates);
148 		Validate.isTrue(predicates.isEmpty() == false);
149 
150 		return platform -> predicates.stream().anyMatch(predicate -> predicate.test(platform));
151 	}
152 
153 	/**
154 	 * Creates a predicate that returns true only if all provided predicates return true (logical AND).
155 	 * 
156 	 * @param predicates array of platform predicates to combine with AND logic
157 	 * @return predicate that returns true only if all input predicates return true
158 	 * @throws IllegalArgumentException if predicates is null or empty
159 	 */
160 	public static Predicate<Platform> and(@SuppressWarnings("unchecked") final Predicate<Platform>... predicates) {
161 		Objects.requireNonNull(predicates);
162 		Validate.isTrue(predicates.length > 0);
163 
164 		return platform -> Arrays.stream(predicates).allMatch(predicate -> predicate.test(platform));
165 	}
166 
167 	/**
168 	 * Creates a predicate that returns true only if all provided predicates return true (logical AND).
169 	 * 
170 	 * @param predicates collection of platform predicates to combine with AND logic
171 	 * @return predicate that returns true only if all input predicates return true
172 	 * @throws IllegalArgumentException if predicates is null or empty
173 	 */
174 	public static Predicate<Platform> and(final Collection<Predicate<Platform>> predicates) {
175 		Objects.requireNonNull(predicates);
176 		Validate.isTrue(predicates.isEmpty() == false);
177 
178 		return platform -> predicates.stream().allMatch(predicate -> predicate.test(platform));
179 	}
180 
181 }