Op.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-6.1.0).
003  * Copyright (c) 2007-2020 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  */
020 package io.jenetics.prog.op;
021 
022 import static java.util.Objects.requireNonNull;
023 
024 import java.util.function.BinaryOperator;
025 import java.util.function.Function;
026 import java.util.function.Supplier;
027 import java.util.function.UnaryOperator;
028 
029 /**
030  * Operation interface. An operation is a function which 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  <pre>{@code
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  * }</pre>
040  *
041  * Implementations of the {@code Op} interface are usually immutable and doesn't
042  * maintain internal state. But some instance 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  */
056 public 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 }