1: <?php
2: 3: 4: 5: 6: 7: 8: 9:
10:
11: namespace chippyash\Type\Number\Complex;
12:
13: use chippyash\Type\AbstractTypeFactory;
14: use chippyash\Type\Exceptions\InvalidTypeException;
15: use chippyash\Type\Number\Rational\RationalType;
16: use chippyash\Type\Number\Rational\GMPRationalType;
17: use chippyash\Type\Number\Rational\AbstractRationalType;
18: use chippyash\Type\Number\Rational\RationalTypeFactory;
19: use chippyash\Type\Number\FloatType;
20: use chippyash\Type\Number\IntType;
21: use chippyash\Type\TypeFactory;
22:
23: 24: 25: 26: 27: 28: 29:
30: abstract class ComplexTypeFactory extends AbstractTypeFactory
31: {
32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46:
47: public static function create($realPart, $imaginaryPart = null)
48: {
49: if (is_string($realPart)) {
50: return self::fromString($realPart);
51: }
52:
53: if (is_null($imaginaryPart)) {
54: throw new \InvalidArgumentException('Imaginary part may not be null if real part is not a string');
55: }
56:
57: $real = self::convertType($realPart);
58: $imaginary = self::convertType($imaginaryPart);
59:
60: if (self::getRequiredType() == self::TYPE_GMP) {
61: return new GMPComplexType($real, $imaginary);
62: } else {
63: return new ComplexType($real, $imaginary);
64: }
65: }
66:
67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77:
78: public static function fromString($string)
79: {
80: $matches = array();
81: $valid = \preg_match(
82: '#^([-,\+])?([0-9]*[\.\/]?[0-9]*)([-,\+]){1}([0-9]*[\.\/]?[0-9]*)i$#',
83: \trim($string),
84: $matches
85: );
86:
87: if ($valid !== 1) {
88: throw new \InvalidArgumentException(
89: 'The string representation of the complex number is invalid.'
90: );
91: }
92:
93: $real = $matches[2];
94: $imaginary = $matches[4];
95:
96: if ($matches[1] && $matches[1] == '-') {
97: $real = '-' . $real;
98: }
99: if ($matches[3] && $matches[3] == '-') {
100: $imaginary = '-' . $imaginary;
101: }
102:
103: return self::create(self::convertType($real), self::convertType($imaginary));
104: }
105:
106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123:
124: public static function fromPolar(AbstractRationalType $radius, AbstractRationalType $theta)
125: {
126: if (self::getRequiredType() == self::TYPE_GMP) {
127: return self::fromGmpPolar($radius, $theta);
128: } else {
129: return self::fromNativePolar($radius, $theta);
130: }
131: }
132:
133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144:
145: public static function fromNativePolar(RationalType $radius, RationalType $theta)
146: {
147: $cos = RationalTypeFactory::fromFloat(cos($theta()));
148: $sin = RationalTypeFactory::fromFloat(sin($theta()));
149:
150: list($realNumerator, $realDenominator) = self::getRealPartsFromRadiusAndCos($radius, $cos);
151: list($imaginaryNumerator, $imaginaryDenominator) = self::getImaginaryPartsFromRadiusAndSin($radius, $sin);
152:
153: $realPart = RationalTypeFactory::create($realNumerator, $realDenominator);
154: $imaginaryPart = RationalTypeFactory::create($imaginaryNumerator, $imaginaryDenominator);
155:
156: return new ComplexType($realPart, $imaginaryPart);
157: }
158:
159: 160: 161: 162: 163: 164: 165: 166:
167: public static function fromGmpPolar(GMPRationalType $radius, GMPRationalType $theta)
168: {
169: $cos = RationalTypeFactory::fromFloat(cos($theta()));
170: $sin = RationalTypeFactory::fromFloat(sin($theta()));
171:
172:
173: $rNum = TypeFactory::create(
174: 'int',
175: gmp_strval(
176: gmp_mul(
177: $radius->numerator()->gmp(),
178: $cos->numerator()->gmp()
179: )
180: )
181: );
182: $rDen = TypeFactory::create(
183: 'int',
184: gmp_strval(
185: gmp_mul(
186: $radius->denominator()->gmp(),
187: $cos->denominator()->gmp()
188: )
189: )
190: );
191:
192: $iNum = TypeFactory::create(
193: 'int',
194: gmp_strval(
195: gmp_mul(
196: $radius->numerator()->gmp(),
197: $sin->numerator()->gmp()
198: )
199: )
200: );
201: $iDen = TypeFactory::create(
202: 'int',
203: gmp_strval(
204: gmp_mul(
205: $radius->denominator()->gmp(),
206: $sin->denominator()->gmp()
207: )
208: )
209: );
210:
211: return new GMPComplexType(
212: RationalTypeFactory::create($rNum, $rDen),
213: RationalTypeFactory::create($iNum, $iDen)
214: );
215: }
216:
217: 218: 219: 220: 221: 222: 223: 224: 225:
226: protected static function convertType($original)
227: {
228: if ($original instanceof AbstractRationalType) {
229: return RationalTypeFactory::create(
230: $original->numerator()->get(),
231: $original->denominator()->get()
232: );
233: }
234: if (is_numeric($original)) {
235: if (is_int($original)) {
236: return RationalTypeFactory::create($original, 1);
237: }
238:
239: return RationalTypeFactory::fromFloat(floatval($original));
240: }
241: if ($original instanceof FloatType) {
242: return RationalTypeFactory::fromFloat($original());
243: }
244: if ($original instanceof IntType) {
245: return RationalTypeFactory::create($original, 1);
246: }
247: if (is_string($original)) {
248: try {
249: return RationalTypeFactory::fromString($original);
250: } catch (\InvalidArgumentException $e) {
251: throw new InvalidTypeException("{$original} for Complex type construction");
252: }
253: }
254:
255: $type = gettype($original);
256: throw new InvalidTypeException("{$type} for Complex type construction");
257: }
258:
259: 260: 261: 262: 263: 264: 265: 266:
267: private static function getRealPartsFromRadiusAndCos(RationalType $radius, RationalType $cos)
268: {
269: return array(
270: TypeFactory::create('int', $radius->numerator()->get() * $cos->numerator()->get()),
271: TypeFactory::create('int', $radius->denominator()->get() * $cos->denominator()->get())
272: ) ;
273: }
274:
275: 276: 277: 278: 279: 280: 281: 282:
283: private static function getImaginaryPartsFromRadiusAndSin(RationalType $radius, RationalType $sin)
284: {
285: return array(
286: TypeFactory::create('int', $radius->numerator()->get() * $sin->numerator()->get()),
287: TypeFactory::create('int', $radius->denominator()->get() * $sin->denominator()->get())
288: ) ;
289: }
290: }
291: