001/* 002 * Java Genetic Algorithm Library (jenetics-8.1.0). 003 * Copyright (c) 2007-2024 Franz Wilhelmstötter 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 * Author: 018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com) 019 */ 020package io.jenetics.prog.op; 021 022import static java.util.Objects.requireNonNull; 023 024import java.util.function.BinaryOperator; 025import java.util.function.Function; 026import java.util.function.Supplier; 027import java.util.function.UnaryOperator; 028 029/** 030 * Operation interface. An operation is a function that maps some argument type 031 * with a given <em>arity</em> to a result object of the same type: 032 * {@code T[] -> T}. 033 * 034 * {@snippet lang="java": 035 * final Op<Double> add = Op.of("add", 2, v -> v[0] + v[1]); 036 * final Op<Double> add3 = Op.of("add3", 3, v -> v[0] + v[1] + v[2]); 037 * final Op<Double> sub = Op.of("sub", 2, v -> v[0] - v[1]); 038 * final Op<Double> sin = Op.of("sin", 1, v -> Math.sin(v[0])); 039 * } 040 * 041 * Implementations of the {@code Op} interface are usually immutable and doesn't 042 * maintain internal state. But some instances are ephemeral with changing state. 043 * This classes must override the {@link #get()} method inherited from the 044 * {@link Supplier} interface and return a new instance. 045 * 046 * @see Var 047 * @see Const 048 * @see EphemeralConst 049 * 050 * @param <T> the argument type of the operation 051 * 052 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 053 * @version 3.9 054 * @since 3.9 055 */ 056public interface Op<T> extends Function<T[], T>, Supplier<Op<T>> { 057 058 /** 059 * Return the name of the operation. 060 * 061 * @return the name of the operation 062 */ 063 String name(); 064 065 /** 066 * Return the arity of the operation function. If the arity is zero, the 067 * operation is <em>terminal</em> operation. 068 * 069 * @return the arity of the operation 070 */ 071 int arity(); 072 073 /** 074 * Determines if the operation is a terminal operation. 075 * 076 * @return {@code true} if the operation is a terminal operation, 077 * {@code false} otherwise 078 */ 079 default boolean isTerminal() { 080 return arity() == 0; 081 } 082 083 /** 084 * Return {@code this} operation, or a new instance from the same type, if 085 * the operation needs to maintain internal state. This is essentially the 086 * case for ephemeral constants. 087 * 088 * @see EphemeralConst 089 * 090 * @return {@code this} operation, or a new instance 091 */ 092 @Override 093 default Op<T> get() { 094 return this; 095 } 096 097 /** 098 * Create a new operation from the given parameter. 099 * 100 * @param name the operation name 101 * @param arity the arity of the operation 102 * @param function the function executed by the operation. In order to work 103 * properly, the given function should be stateless and must not have 104 * side effects. 105 * @param <T> the operation type 106 * @return a new operation from the given parameter 107 * @throws NullPointerException if the given {@code name} or {@code function} 108 * is {@code null} 109 * @throws IllegalArgumentException if the given {@code arity} is smaller 110 * than zero 111 */ 112 static <T> Op<T> of( 113 final String name, 114 final int arity, 115 final Function<T[], T> function 116 ) { 117 return new Operation<>(name, arity, function); 118 } 119 120 /** 121 * Create a new operation with the given name and unary operation. The 122 * returned {@code Op} will have arity one. 123 * 124 * @since 4.0 125 * 126 * @param name the name of the returned operation 127 * @param function the used function of the operation 128 * @param <T> the operation type 129 * @return a new operation with the given name and unary operation 130 * @throws NullPointerException if the given {@code name} or {@code function} 131 * is {@code null} 132 */ 133 static <T> Op<T> of( 134 final String name, 135 final UnaryOperator<T> function 136 ) { 137 requireNonNull(function); 138 return of(name, 1, v -> function.apply(v[0])); 139 } 140 141 /** 142 * Create a new operation with the given name and binary operation. The 143 * returned {@code Op} will have arity two. 144 * 145 * @since 4.0 146 * 147 * @param name the name of the returned operation 148 * @param function the used function of the operation 149 * @param <T> the operation type 150 * @return a new operation with the given name and unary operation 151 * @throws NullPointerException if the given {@code name} or {@code function} 152 * is {@code null} 153 */ 154 static <T> Op<T> of( 155 final String name, 156 final BinaryOperator<T> function 157 ) { 158 requireNonNull(function); 159 return of(name, 2, v -> function.apply(v[0], v[1])); 160 } 161 162}