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.ext;
021
022import static io.jenetics.internal.util.SerialIO.readBytes;
023import static io.jenetics.internal.util.SerialIO.readInt;
024import static io.jenetics.internal.util.SerialIO.writeBytes;
025import static io.jenetics.internal.util.SerialIO.writeInt;
026
027import java.io.DataInput;
028import java.io.DataOutput;
029import java.io.IOException;
030import java.io.InvalidObjectException;
031import java.io.ObjectInputStream;
032import java.io.Serial;
033import java.io.Serializable;
034import java.math.BigInteger;
035
036import io.jenetics.AbstractChromosome;
037import io.jenetics.DoubleGene;
038import io.jenetics.NumericChromosome;
039import io.jenetics.util.ISeq;
040import io.jenetics.util.MSeq;
041
042/**
043 * Numeric chromosome implementation which holds arbitrary sized integer numbers.
044 *
045 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
046 * @version 5.2
047 * @since 3.5
048 */
049public class BigIntegerChromosome
050        extends AbstractChromosome<BigIntegerGene>
051        implements
052                NumericChromosome<BigInteger, BigIntegerGene>,
053                Serializable
054{
055
056        @Serial
057        private static final long serialVersionUID = 1L;
058
059        private final BigInteger _min;
060        private final BigInteger _max;
061
062        /**
063         * Create a new chromosome from the given genes array.
064         *
065         * @param genes the genes of the new chromosome.
066         * @throws IllegalArgumentException if the {@code genes.length()} is smaller
067         *         than one.
068         * @throws NullPointerException if the {@code genes} are {@code null}.
069         * @throws IllegalArgumentException if the gene sequence is empty
070         */
071        protected BigIntegerChromosome(final ISeq<BigIntegerGene> genes) {
072                super(genes);
073                _min = genes.get(0).min();
074                _max = genes.get(0).max();
075        }
076
077        /**
078         * Create a new random {@code BigIntegerChromosome} with the given
079         * {@code length}.
080         *
081         * @param min the min value of the {@link BigIntegerGene}s (inclusively).
082         * @param max the max value of the {@link BigIntegerGene}s (exclusively).
083         * @param length the length of the chromosome.
084         * @throws NullPointerException if one of the arguments is {@code null}.
085         * @throws IllegalArgumentException if the {@code length} is smaller than
086         *         one.
087         */
088        public BigIntegerChromosome(
089                final BigInteger min,
090                final BigInteger max,
091                final int length
092        ) {
093                this(BigIntegerGene.seq(min, max, length));
094                _valid = true;
095        }
096
097        /**
098         * Create a new random {@code DoubleChromosome} of length one.
099         *
100         * @param min the minimal value of this chromosome (inclusively).
101         * @param max the maximal value of this chromosome (exclusively).
102         * @throws NullPointerException if one of the arguments is {@code null}.
103         */
104        public BigIntegerChromosome(final BigInteger min, final BigInteger max) {
105                this(min, max, 1);
106        }
107
108        @Override
109        public BigInteger min() {
110                return _min;
111        }
112
113        @Override
114        public BigInteger max() {
115                return _max;
116        }
117
118        @Override
119        public BigIntegerChromosome newInstance(final ISeq<BigIntegerGene> genes) {
120                return new BigIntegerChromosome(genes);
121        }
122
123        @Override
124        public BigIntegerChromosome newInstance() {
125                return new BigIntegerChromosome(_min, _max, length());
126        }
127
128        /* *************************************************************************
129         * Static factory methods.
130         **************************************************************************/
131
132        /**
133         * Create a new {@code DoubleChromosome} with the given genes.
134         *
135         * @param genes the genes of the chromosome.
136         * @return a new chromosome with the given genes.
137         * @throws IllegalArgumentException if the length of the genes array is
138         *         empty.
139         * @throws NullPointerException if the given {@code genes} array is
140         *         {@code null}
141         */
142        public static BigIntegerChromosome of(final BigIntegerGene... genes) {
143                return new BigIntegerChromosome(ISeq.of(genes));
144        }
145
146        /**
147         * Create a new random {@code DoubleChromosome}.
148         *
149         * @param min the min value of the {@link DoubleGene}s (inclusively).
150         * @param max the max value of the {@link DoubleGene}s (exclusively).
151         * @param length the length of the chromosome.
152         * @return a new {@code DoubleChromosome} with the given parameter
153         */
154        public static BigIntegerChromosome of(final BigInteger min, BigInteger max, final int length) {
155                return new BigIntegerChromosome(min, max, length);
156        }
157
158        /**
159         * Create a new random {@code DoubleChromosome} of length one.
160         *
161         * @param min the minimal value of this chromosome (inclusively).
162         * @param max the maximal value of this chromosome (exclusively).
163         * @return a new {@code DoubleChromosome} with the given parameter
164         */
165        public static BigIntegerChromosome of(final BigInteger min, final BigInteger max) {
166                return new BigIntegerChromosome(min, max);
167        }
168
169        /* *************************************************************************
170         *  Java object serialization
171         * ************************************************************************/
172
173        @Serial
174        private Object writeReplace() {
175                return new SerialProxy(SerialProxy.BIG_INTEGER_CHROMOSOME, this);
176        }
177
178        @Serial
179        private void readObject(final ObjectInputStream stream)
180                throws InvalidObjectException
181        {
182                throw new InvalidObjectException("Serialization proxy required.");
183        }
184
185        void write(final DataOutput out) throws IOException {
186                writeInt(length(), out);
187                writeBytes(_min.toByteArray(), out);
188                writeBytes(_max.toByteArray(), out);
189
190                for (BigIntegerGene gene : _genes) {
191                        writeBytes(gene.allele().toByteArray(), out);
192                }
193        }
194
195        static BigIntegerChromosome read(final DataInput in) throws IOException {
196                final var length = readInt(in);
197                final var min = new BigInteger(readBytes(in));
198                final var max = new BigInteger(readBytes(in));
199
200                final MSeq<BigIntegerGene> genes = MSeq.ofLength(length);
201                for (int i = 0; i < length; ++i) {
202                        final BigInteger value = new BigInteger(readBytes(in));
203                        genes.set(i, BigIntegerGene.of(value, min, max));
204                }
205
206                return new BigIntegerChromosome(genes.toISeq());
207        }
208
209}