1+ module  TestAdvancedArithmetic
2+ 
3+ using  MultidimensionalSparseArrays
4+ using  Test
5+ 
6+ @testset  " Advanced Arithmetic Operations"   begin 
7+     @testset  " Addition Edge Cases"   begin 
8+         #  Test addition with completely disjoint sparse patterns
9+         A =  SparseArray {Int, 2} ((3 , 3 ))
10+         A[1 , 1 ] =  5 
11+         A[2 , 2 ] =  10 
12+         
13+         B =  SparseArray {Int, 2} ((3 , 3 ))
14+         B[1 , 3 ] =  3 
15+         B[3 , 1 ] =  7 
16+         
17+         C =  A +  B
18+         @test  C[1 , 1 ] ==  5 
19+         @test  C[2 , 2 ] ==  10 
20+         @test  C[1 , 3 ] ==  3 
21+         @test  C[3 , 1 ] ==  7 
22+         @test  nnz (C) ==  4 
23+         @test  ! hasindex (C, 2 , 1 )
24+         @test  ! hasindex (C, 3 , 3 )
25+         
26+         #  Test addition with overlapping indices
27+         D =  SparseArray {Int, 2} ((3 , 3 ))
28+         D[1 , 1 ] =  2 
29+         D[2 , 3 ] =  8 
30+         
31+         E =  A +  D
32+         @test  E[1 , 1 ] ==  7   #  5 + 2
33+         @test  E[2 , 2 ] ==  10   #  10 + 0 (D doesn't have [2,2])
34+         @test  E[2 , 3 ] ==  8    #  0 + 8 (A doesn't have [2,3])
35+         @test  nnz (E) ==  3 
36+     end 
37+     
38+     @testset  " Subtraction with Zero Results"   begin 
39+         A =  SparseArray {Int, 2} ((3 , 3 ))
40+         A[1 , 1 ] =  5 
41+         A[2 , 2 ] =  10 
42+         A[1 , 3 ] =  7 
43+         
44+         B =  SparseArray {Int, 2} ((3 , 3 ))
45+         B[1 , 1 ] =  5   #  Same as A[1,1] - should result in zero
46+         B[2 , 2 ] =  3   #  Different from A[2,2]
47+         B[3 , 1 ] =  4   #  Not in A
48+         
49+         C =  A -  B
50+         @test  ! hasindex (C, 1 , 1 )  #  5 - 5 = 0, not stored
51+         @test  C[2 , 2 ] ==  7         #  10 - 3 = 7
52+         @test  C[1 , 3 ] ==  7         #  7 - 0 = 7
53+         @test  C[3 , 1 ] ==  - 4        #  0 - 4 = -4
54+         @test  nnz (C) ==  3 
55+     end 
56+     
57+     @testset  " Type Promotion in Arithmetic"   begin 
58+         #  Int + Float64
59+         A =  SparseArray {Int, 2} ((2 , 2 ))
60+         A[1 , 1 ] =  5 
61+         
62+         B =  SparseArray {Float64, 2} ((2 , 2 ))
63+         B[1 , 1 ] =  2.5 
64+         B[2 , 2 ] =  3.7 
65+         
66+         C =  A +  B
67+         @test  eltype (C) ==  Float64
68+         @test  C[1 , 1 ] ==  7.5 
69+         @test  C[2 , 2 ] ==  3.7 
70+         
71+         #  Int + Complex
72+         D =  SparseArray {Complex{Float64}, 2} ((2 , 2 ))
73+         D[1 , 1 ] =  1.0  +  2.0im 
74+         
75+         E =  A +  D
76+         @test  eltype (E) ==  Complex{Float64}
77+         @test  E[1 , 1 ] ==  6.0  +  2.0im 
78+         
79+         #  Rational arithmetic
80+         F =  SparseArray {Rational{Int}, 2} ((2 , 2 ))
81+         F[1 , 1 ] =  1 // 3 
82+         
83+         G =  SparseArray {Rational{Int}, 2} ((2 , 2 ))
84+         G[1 , 1 ] =  1 // 6 
85+         G[2 , 1 ] =  2 // 3 
86+         
87+         H =  F +  G
88+         @test  H[1 , 1 ] ==  1 // 2   #  1/3 + 1/6 = 1/2
89+         @test  H[2 , 1 ] ==  2 // 3 
90+     end 
91+     
92+     @testset  " Scalar Multiplication Edge Cases"   begin 
93+         A =  SparseArray {Float64, 2} ((3 , 3 ))
94+         A[1 , 1 ] =  2.0 
95+         A[2 , 3 ] =  - 1.5 
96+         A[3 , 2 ] =  0.0   #  Explicitly stored zero
97+         
98+         #  Multiplication by zero
99+         B =  A *  0 
100+         @test  nnz (B) ==  0   #  All values become zero, nothing stored
101+         
102+         #  Multiplication by negative number
103+         C =  A *  (- 2 )
104+         @test  C[1 , 1 ] ==  - 4.0 
105+         @test  C[2 , 3 ] ==  3.0 
106+         @test  C[3 , 2 ] ==  0.0 
107+         @test  nnz (C) ==  3   #  Zero is still stored
108+         
109+         #  Multiplication by complex number
110+         D =  A *  (1  +  1im )
111+         @test  eltype (D) ==  Complex{Float64}
112+         @test  D[1 , 1 ] ==  2.0  +  2.0im 
113+         @test  D[2 , 3 ] ==  - 1.5  -  1.5im 
114+         
115+         #  Left multiplication
116+         E =  (2  +  3im ) *  A
117+         @test  E[1 , 1 ] ==  4.0  +  6.0im 
118+         @test  E[2 , 3 ] ==  - 3.0  -  4.5im 
119+     end 
120+     
121+     @testset  " Large Sparse Array Arithmetic"   begin 
122+         #  Test arithmetic on larger arrays to ensure efficiency
123+         A =  SparseArray {Float64, 2} ((100 , 100 ))
124+         B =  SparseArray {Float64, 2} ((100 , 100 ))
125+         
126+         #  Add sparse diagonal pattern
127+         for  i in  1 : 10 : 100 
128+             A[i, i] =  Float64 (i)
129+             B[i, i] =  Float64 (i) *  0.5 
130+         end 
131+         
132+         #  Add some off-diagonal elements
133+         A[25 , 75 ] =  12.5 
134+         B[75 , 25 ] =  8.3 
135+         
136+         C =  A +  B
137+         @test  nnz (C) ==  12   #  10 diagonal + 2 off-diagonal
138+         @test  C[11 , 11 ] ==  16.5   #  11 + 5.5
139+         @test  C[25 , 75 ] ==  12.5 
140+         @test  C[75 , 25 ] ==  8.3 
141+         
142+         #  Scalar multiplication should preserve sparsity
143+         D =  A *  2.0 
144+         @test  nnz (D) ==  nnz (A)
145+     end 
146+     
147+     @testset  " Arithmetic with Different Dimensions"   begin 
148+         A =  SparseArray {Int, 3} ((2 , 2 , 2 ))
149+         A[1 , 1 , 1 ] =  5 
150+         A[2 , 2 , 2 ] =  10 
151+         
152+         B =  SparseArray {Int, 3} ((2 , 2 , 2 ))
153+         B[1 , 1 , 1 ] =  3 
154+         B[1 , 2 , 1 ] =  7 
155+         
156+         C =  A +  B
157+         @test  C[1 , 1 , 1 ] ==  8 
158+         @test  C[2 , 2 , 2 ] ==  10 
159+         @test  C[1 , 2 , 1 ] ==  7 
160+         @test  nnz (C) ==  3 
161+     end 
162+     
163+     @testset  " Arithmetic Result Optimization"   begin 
164+         #  Test that arithmetic operations don't store unnecessary zeros
165+         A =  SparseArray {Float64, 2} ((3 , 3 ))
166+         A[1 , 1 ] =  5.0 
167+         A[2 , 2 ] =  3.0 
168+         
169+         B =  SparseArray {Float64, 2} ((3 , 3 ))
170+         B[1 , 1 ] =  5.0   #  Will cancel out in subtraction
171+         B[3 , 3 ] =  2.0 
172+         
173+         C =  A -  B
174+         @test  ! hasindex (C, 1 , 1 )  #  Should not store 5.0 - 5.0 = 0.0
175+         @test  C[2 , 2 ] ==  3.0 
176+         @test  C[3 , 3 ] ==  - 2.0 
177+         @test  nnz (C) ==  2 
178+     end 
179+     
180+     @testset  " Precision and Floating Point Arithmetic"   begin 
181+         A =  SparseArray {Float64, 2} ((2 , 2 ))
182+         A[1 , 1 ] =  0.1  +  0.2   #  This is 0.30000000000000004 in floating point
183+         
184+         B =  SparseArray {Float64, 2} ((2 , 2 ))
185+         B[1 , 1 ] =  0.3 
186+         
187+         C =  A -  B
188+         #  The result should be close to zero but not exactly zero due to floating point precision
189+         @test  hasindex (C, 1 , 1 )
190+         @test  abs (C[1 , 1 ]) <  1e-15 
191+         @test  C[1 , 1 ] !=  0.0 
192+     end 
193+     
194+     @testset  " Chain Operations"   begin 
195+         A =  SparseArray {Int, 2} ((3 , 3 ))
196+         A[1 , 1 ] =  1 
197+         A[2 , 2 ] =  2 
198+         
199+         B =  SparseArray {Int, 2} ((3 , 3 ))
200+         B[1 , 1 ] =  1 
201+         B[1 , 3 ] =  3 
202+         
203+         C =  SparseArray {Int, 2} ((3 , 3 ))
204+         C[2 , 2 ] =  1 
205+         C[3 , 1 ] =  4 
206+         
207+         #  Test (A + B) - C
208+         D =  (A +  B) -  C
209+         @test  D[1 , 1 ] ==  2    #  (1 + 1) - 0 = 2
210+         @test  D[2 , 2 ] ==  1    #  (2 + 0) - 1 = 1
211+         @test  D[1 , 3 ] ==  3    #  (0 + 3) - 0 = 3
212+         @test  D[3 , 1 ] ==  - 4   #  (0 + 0) - 4 = -4
213+         @test  nnz (D) ==  4 
214+     end 
215+ end 
216+ 
217+ end 
0 commit comments