1############################################################################# 2## 3## This file is part of GAP, a system for computational discrete algebra. 4## 5## Copyright of GAP belongs to its developers, whose names are too numerous 6## to list here. Please refer to the COPYRIGHT file for details. 7## 8## SPDX-License-Identifier: GPL-2.0-or-later 9## 10 11############################################################################# 12## 13## Parametrize the output; if `error' has the value `Error' then only the 14## first error in each call is printed in the `Test' run, 15## if the value is `Print' then all errors are printed. 16## 17error:= Print;; 18 19############################################################################# 20## 21## How many times to repeat the same tests? Large values result in longer 22## test runs, but with a higher probability of finding bugs 23## 24ARITH_LST_REPS := 5; 25 26 27############################################################################# 28## 29## Define auxiliary functions. 30## 31RandomSquareArray := function( dim, D ) 32 return List( [ 1 .. dim ], i -> List( [ 1 .. dim ], j -> Random( D ) ) ); 33end;; 34NestingDepthATest := function( obj ) 35 if not IsGeneralizedRowVector( obj ) then 36 return 0; 37 elif IsEmpty( obj ) then 38 return 1; 39 else 40 return 1 + NestingDepthATest( obj[ PositionBound( obj ) ] ); 41 fi; 42end;; 43NestingDepthMTest := function( obj ) 44 if not IsMultiplicativeGeneralizedRowVector( obj ) then 45 return 0; 46 elif IsEmpty( obj ) then 47 return 1; 48 else 49 return 1 + NestingDepthMTest( obj[ PositionBound( obj ) ] ); 50 fi; 51end;; 52ImmutabilityLevel2 := function( list ) 53 if not IsList( list ) then 54 if IsMutable( list ) then 55 Error( "<list> is not a list" ); 56 else 57 return 0; 58 fi; 59 elif IsEmpty( list ) then 60 # The empty list is defined to have immutability level 0. 61 return 0; 62 elif IsMutable( list ) then 63 return ImmutabilityLevel2( list[ PositionBound( list ) ] ); 64 else 65 return 1 + ImmutabilityLevel2( list[ PositionBound( list ) ] ); 66 fi; 67end;; 68ImmutabilityLevel := function( list ) 69 if IsMutable( list ) then 70 return ImmutabilityLevel2( list ); 71 else 72 return infinity; 73 fi; 74end;; 75 76## Note that the two-argument version of `List' is defined only for 77## dense lists. 78ListWithPrescribedHoles := function( list, func ) 79 local result, i; 80 81 result:= []; 82 for i in [ 1 .. Length( list ) ] do 83 if IsBound( list[i] ) then 84 result[i]:= func( list[i] ); 85 fi; 86 od; 87 return result; 88end;; 89SumWithHoles := function( list ) 90 local pos, result, i; 91 92 pos:= PositionBound( list ); 93 result:= list[ pos ]; 94 for i in [ pos+1 .. Length( list ) ] do 95 if IsBound( list[i] ) then 96 result:= result + list[i]; 97 fi; 98 od; 99 return result; 100end;; 101ParallelOp := function( op, list1, list2, mode ) 102 local result, i; 103 104 result:= []; 105 for i in [ 1 .. Maximum( Length( list1 ), Length( list2 ) ) ] do 106 if IsBound( list1[i] ) then 107 if IsBound( list2[i] ) then 108 result[i]:= op( list1[i], list2[i] ); 109 elif mode = "one" then 110 result[i]:= ShallowCopy( list1[i] ); 111 fi; 112 elif IsBound( list2[i] ) and mode = "one" then 113 result[i]:= ShallowCopy( list2[i] ); 114 fi; 115 od; 116 return result; 117end;; 118ErrorMessage := function( opname, operands, info, is, should ) 119 local str, i; 120 121 str:= Concatenation( opname, "( " ); 122 for i in [ 1 .. Length( operands ) - 1 ] do 123 Append( str, operands[i] ); 124 Append( str, ", " ); 125 od; 126 error( str, operands[ Length( operands ) ], " ): ", info, ",\n", 127 "should be ", should, " but is ", is, "\n" ); 128end;; 129CheckMutabilityStatus := function( opname, list ) 130 local attr, op, val, sm; 131 132 attr:= ValueGlobal( Concatenation( opname, "Attr" ) ); 133 if ImmutabilityLevel( attr( list ) ) <> infinity then 134 error( opname, "Attr: mutability problem for ", list, 135 " (", ImmutabilityLevel( list ), ")\n" ); 136 fi; 137 op:= ValueGlobal( Concatenation( opname, "Op" ) ); 138 val:= op( list ); 139 if val <> fail and IsCopyable( val ) and not IsMutable( val ) then 140 error( opname, "Op: mutability problem for ", list, 141 " (", ImmutabilityLevel( list ), ")\n" ); 142 fi; 143 sm:= ValueGlobal( Concatenation( opname, "SM" ) ); 144 val:= sm( list ); 145 if val <> fail 146 and IsCopyable( val ) 147 and ImmutabilityLevel( sm( list ) ) <> ImmutabilityLevel( list ) then 148 error( opname, "SM: mutability problem for ", list, 149 " (", ImmutabilityLevel( list ), ")\n" ); 150 fi; 151end;; 152 153## Check whether a unary operation preserves the compression status. 154COMPRESSIONS := [ "Is8BitMatrixRep", "Is8BitVectorRep", 155 "IsGF2VectorRep", "IsGF2MatrixRep" ];; 156CheckCompressionStatus := function( opname, list ) 157 local value, namefilter, filter; 158 159 value:= ValueGlobal( opname )( list ); 160 if value <> fail then 161 for namefilter in COMPRESSIONS do 162 filter:= ValueGlobal( namefilter ); 163 if filter( list ) and not filter( value ) then 164 error( opname, " does not preserve `", namefilter, "'\n" ); 165 fi; 166 od; 167 fi; 168end;; 169CompareTest := function( opname, operands, result, desired ) 170 local i, j, val; 171 172 # Check that the same positions are bound, 173 # and that corresponding entries are equal. 174 if IsList( result ) and IsList( desired ) then 175 if Length( result ) <> Length( desired ) then 176 ErrorMessage( opname, operands, "lengths differ", 177 Length( result ), Length( desired ) ); 178 fi; 179 for i in [ 1 .. Length( result ) ] do 180 if IsBound( result[i] ) then 181 if not IsBound( desired[i] ) then 182 ErrorMessage( opname, operands, 183 Concatenation( "bound at ", String( i ) ), 184 result[i], "unbound" ); 185 elif result[i] <> desired[i] then 186 ErrorMessage( opname, operands, 187 Concatenation( "error at ", String( i ) ), 188 result[i], desired[i] ); 189 fi; 190 elif IsBound( desired[i] ) then 191 ErrorMessage( opname, operands, 192 Concatenation( "unbound at ", String( i ) ), 193 "unbound", desired[i] ); 194 fi; 195 od; 196 elif IsList( result ) or IsList( desired ) then 197 ErrorMessage( opname, operands, "list vs. non-list", result, desired ); 198 elif result <> desired then 199 ErrorMessage( opname, operands, "two non-lists", result, desired ); 200 fi; 201 202 # Check the mutability status. 203 if Length( operands ) = 2 204 and IsList( result ) and IsCopyable( result ) 205 and ImmutabilityLevel( result ) 206 <> Minimum( List( operands, ImmutabilityLevel ) ) 207 and not (ImmutabilityLevel(result)=infinity and 208 NestingDepthM(result) = 209 Minimum( List( operands, ImmutabilityLevel ) )) then 210 error( opname, ": mutability problem for ", operands[1], " (", 211 ImmutabilityLevel( operands[1] ), ") and ", operands[2], " (", 212 ImmutabilityLevel( operands[2] ), ")\n" ); 213 fi; 214end;; 215 216############################################################################# 217## 218#F ZeroTest( <list> ) 219## 220## The zero of a list $x$ in `IsGeneralizedRowVector' is defined as 221## the list whose entry at position $i$ is the zero of $x[i]$ 222## if this entry is bound, and is unbound otherwise. 223## 224ZeroTest := function( list ) 225 if IsGeneralizedRowVector( list ) then 226 CompareTest( "Zero", [ list ], 227 Zero( list ), 228 ListWithPrescribedHoles( list, Zero ) ); 229 CheckMutabilityStatus( "Zero", list ); 230 CheckCompressionStatus( "ZeroAttr", list ); 231 CheckCompressionStatus( "ZeroSM", list ); 232 fi; 233end;; 234 235############################################################################# 236## 237#F AdditiveInverseTest( <list> ) 238## 239## The additive inverse of a list $x$ in `IsGeneralizedRowVector' is defined 240## as the list whose entry at position $i$ is the additive inverse of $x[i]$ 241## if this entry is bound, and is unbound otherwise. 242## 243AdditiveInverseTest := function( list ) 244 if IsGeneralizedRowVector( list ) then 245 CompareTest( "AdditiveInverse", [ list ], 246 AdditiveInverse( list ), 247 ListWithPrescribedHoles( list, AdditiveInverse ) ); 248 CheckMutabilityStatus( "AdditiveInverse", list ); 249 CheckCompressionStatus( "AdditiveInverseAttr", list ); 250 CheckCompressionStatus( "AdditiveInverseSM", list ); 251 fi; 252end;; 253 254############################################################################# 255## 256#F AdditionTest( <left>, <right> ) 257## 258## If $x$ and $y$ are in `IsGeneralizedRowVector' and have the same 259## additive nesting depth (see~"NestingDepthA"), 260## % By definition, this depth is nonzero. 261## the sum $x + y$ is defined *pointwise*, in the sense that the result is a 262## list whose entry at position $i$ is $x[i] + y[i]$ if these entries are 263## bound, 264## is a shallow copy (see~"ShallowCopy") of $x[i]$ or $y[i]$ if the other 265## argument is not bound at position $i$, 266## and is unbound if both $x$ and $y$ are unbound at position $i$. 267## 268## If $x$ is in `IsGeneralizedRowVector' and $y$ is either not a list or is 269## in `IsGeneralizedRowVector' and has lower additive nesting depth, 270## the sum $x + y$ is defined as a list whose entry at position $i$ is 271## $x[i] + y$ if $x$ is bound at position $i$, and is unbound if not. 272## The equivalent holds in the reversed case, 273## where the order of the summands is kept, 274## as addition is not always commutative. 275## 276## For two {\GAP} objects $x$ and $y$ of which one is in 277## `IsGeneralizedRowVector' and the other is either not a list or is 278## also in `IsGeneralizedRowVector', 279## $x - y$ is defined as $x + (-y)$. 280## 281AdditionTest := function( left, right ) 282 local depth1, depth2, desired; 283 284 if IsGeneralizedRowVector( left ) and IsGeneralizedRowVector( right ) then 285 depth1:= NestingDepthATest( left ); 286 depth2:= NestingDepthATest( right ); 287 if depth1 = depth2 then 288 desired:= ParallelOp( \+, left, right, "one" ); 289 elif depth1 < depth2 then 290 desired:= ListWithPrescribedHoles( right, x -> left + x ); 291 else 292 desired:= ListWithPrescribedHoles( left, x -> x + right ); 293 fi; 294 elif IsGeneralizedRowVector( left ) and not IsList( right ) then 295 desired:= ListWithPrescribedHoles( left, x -> x + right ); 296 elif not IsList( left ) and IsGeneralizedRowVector( right ) then 297 desired:= ListWithPrescribedHoles( right, x -> left + x ); 298 else 299 return; 300 fi; 301 CompareTest( "Addition", [ left, right ], left + right, desired ); 302 if AdditiveInverse( right ) <> fail then 303 CompareTest( "Subtraction", [ left, right ], left - right, 304 left + ( - right ) ); 305 fi; 306end;; 307 308############################################################################# 309## 310#F OneTest( <list> ) 311## 312OneTest := function( list ) 313 if IsOrdinaryMatrix( list ) and Length( list ) = Length( list[1] ) then 314 CheckMutabilityStatus( "One", list ); 315 CheckCompressionStatus( "OneAttr", list ); 316 CheckCompressionStatus( "OneSM", list ); 317 fi; 318end;; 319 320############################################################################# 321## 322#F InverseTest( <obj> ) 323## 324InverseTest := function( list ) 325 if IsOrdinaryMatrix( list ) and Length( list ) = Length( list[1] ) then 326 CheckMutabilityStatus( "Inverse", list ); 327 CheckCompressionStatus( "InverseAttr", list ); 328 CheckCompressionStatus( "InverseSM", list ); 329 fi; 330end;; 331 332############################################################################# 333## 334#F TransposedMatTest( <obj> ) 335## 336TransposedMatTest := function( list ) 337 if IsOrdinaryMatrix( list ) then 338 CheckCompressionStatus( "TransposedMatAttr", list ); 339 CheckCompressionStatus( "TransposedMatOp", list ); 340 fi; 341end;; 342 343############################################################################# 344## 345#F MultiplicationTest( <left>, <right> ) 346## 347## There are three possible computations that might be triggered by a 348## multiplication involving a list in 349## `IsMultiplicativeGeneralizedRowVector'. 350## Namely, $x * y$ might be 351## \beginlist 352## \item{(I)} 353## the inner product $x[1] * y[1] + x[2] * y[2] + \cdots + x[n] * y[n]$, 354## where summands are omitted for which the entry in $x$ or $y$ is 355## unbound 356## (if this leaves no summand then the multiplication is an error), 357## or 358## \item{(L)} 359## the left scalar multiple, i.e., a list whose entry at position $i$ is 360## $x * y[i]$ if $y$ is bound at position $i$, and is unbound if not, or 361## \item{(R)} 362## the right scalar multiple, i.e., a list whose entry at position $i$ 363## is $x[i] * y$ if $x$ is bound at position $i$, and is unbound if not. 364## \endlist 365## 366## Our aim is to generalize the basic arithmetic of simple row vectors and 367## matrices, so we first summarize the situations that shall be covered. 368## 369## \beginexample 370## | scl vec mat 371## --------------------- 372## scl | (L) (L) 373## vec | (R) (I) (I) 374## mat | (R) (R) (R) 375## \endexample 376## 377## This means for example that the product of a scalar (scl) 378## with a vector (vec) or a matrix (mat) is computed according to (L). 379## Note that this is asymmetric. 380## 381## Now we can state the general multiplication rules. 382## 383## If exactly one argument is in `IsMultiplicativeGeneralizedRowVector' 384## then we regard the other argument (which is then not a list) as a scalar, 385## and specify result (L) or (R), depending on ordering. 386## 387## In the remaining cases, both $x$ and $y$ are in 388## `IsMultiplicativeGeneralizedRowVector', and we distinguish the 389## possibilities by their multiplicative nesting depths. 390## An argument with *odd* multiplicative nesting depth is regarded as a 391## vector, and an argument with *even* multiplicative nesting depth is 392## regarded as a scalar or a matrix. 393## 394## So if both arguments have odd multiplicative nesting depth, 395## we specify result (I). 396## 397## If exactly one argument has odd nesting depth, 398## the other is treated as a scalar if it has lower multiplicative nesting 399## depth, and as a matrix otherwise. 400## In the former case, we specify result (L) or (R), depending on ordering; 401## in the latter case, we specify result (L) or (I), depending on ordering. 402## 403## We are left with the case that each argument has even multiplicative 404## nesting depth. 405## % By definition, this depth is nonzero. 406## If the two depths are equal, we treat the computation as a matrix product, 407## and specify result (R). 408## Otherwise, we treat the less deeply nested argument as a scalar and the 409## other as a matrix, and specify result (L) or (R), depending on ordering. 410## 411## For two {\GAP} objects $x$ and $y$ of which one is in 412## `IsMultiplicativeGeneralizedRowVector' and the other is either not a list 413## or is also in `IsMultiplicativeGeneralizedRowVector', 414## $x / y$ is defined as $x * y^{-1}$. 415## 416MultiplicationTest := function( left, right ) 417 local depth1, depth2, par, desired; 418 419 if IsMultiplicativeGeneralizedRowVector( left ) and 420 IsMultiplicativeGeneralizedRowVector( right ) then 421 depth1:= NestingDepthMTest( left ); 422 depth2:= NestingDepthMTest( right ); 423 if IsOddInt( depth1 ) then 424 if IsOddInt( depth2 ) or depth1 < depth2 then 425 # <vec> * <vec> or <vec> * <mat> 426 par:= ParallelOp( \*, left, right, "both" ); 427 if IsEmpty( par ) then 428 error( "vector multiplication <left>*<right> with empty ", 429 "support:\n", left, "\n", right, "\n" ); 430 else 431 desired:= SumWithHoles( par ); 432 fi; 433 else 434 # <vec> * <scl> 435 desired:= ListWithPrescribedHoles( left, x -> x * right ); 436 fi; 437 elif IsOddInt( depth2 ) then 438 if depth1 < depth2 then 439 # <scl> * <vec> 440 desired:= ListWithPrescribedHoles( right, x -> left * x ); 441 else 442 # <mat> * <vec> 443 desired:= ListWithPrescribedHoles( left, x -> x * right ); 444 fi; 445 elif depth1 = depth2 then 446 # <mat> * <mat> 447 desired:= ListWithPrescribedHoles( left, x -> x * right ); 448 elif depth1 < depth2 then 449 # <scl> * <mat> 450 desired:= ListWithPrescribedHoles( right, x -> left * x ); 451 else 452 # <mat> * <scl> 453 desired:= ListWithPrescribedHoles( left, x -> x * right ); 454 fi; 455 elif IsMultiplicativeGeneralizedRowVector( left ) and 456 not IsList( right ) then 457 desired:= ListWithPrescribedHoles( left, x -> x * right ); 458 elif IsMultiplicativeGeneralizedRowVector( right ) and 459 not IsList( left ) then 460 desired:= ListWithPrescribedHoles( right, x -> left * x ); 461 else 462 return; 463 fi; 464 CompareTest( "Multiplication", [ left, right ], left * right, desired ); 465 if IsMultiplicativeGeneralizedRowVector( right ) 466 and IsOrdinaryMatrix( right ) 467 and Length( right ) = Length( right[1] ) 468 and NestingDepthM( right ) = 2 469 and Inverse( right ) <> fail then 470 CompareTest( "Division", [ left, right ], left / right, 471 left * ( right^-1 ) ); 472 fi; 473end;; 474 475############################################################################# 476## 477#F RunTest( <func>, <arg1>, ... ) 478## 479## Call <func> for the remaining arguments, or for shallow copies of them 480## or immutable copies. 481## 482RunTest := function( arg ) 483 local combinations, i, entry; 484 485 combinations:= [ ]; 486 for i in [ 2 .. Length( arg ) ] do 487 entry:= [ arg[i] ]; 488 if IsCopyable( arg[i] ) then 489 Add( entry, ShallowCopy( arg[i] ) ); 490 fi; 491 if IsMutable( arg[i] ) then 492 Add( entry, Immutable( arg[i] ) ); 493 fi; 494 Add( combinations, entry ); 495 od; 496 for entry in Cartesian( combinations ) do 497 CallFuncList( arg[1], entry ); 498 od; 499end;; 500 501############################################################################# 502## 503#F TestOfAdditiveListArithmetic( <R>, <dim> ) 504## 505## For a ring or list of ring elements <R> (such that `Random( <R> )' 506## returns an element in <R> and such that not all elements in <R> are 507## zero), 508## `TestOfAdditiveListArithmetic' performs the following tests of additive 509## arithmetic operations. 510## \beginlist 511## \item{1.} 512## If the elements of <R> are in `IsGeneralizedRowVector' then 513## it is checked whether `Zero', `AdditiveInverse', and `\+' 514## obey the definitions. 515## \item{2.} 516## If the elements of <R> are in `IsGeneralizedRowVector' then 517## it is checked whether the sum of elements in <R> and (non-dense) 518## plain lists of integers obeys the definitions. 519## \item{3.} 520## Check `Zero' and `AdditiveInverse' for nested plain lists of elements 521## in <R>, and `\+' for elements in <R> and nested plain lists of 522## elements in <R>. 523## \endlist 524## 525TestOfAdditiveListArithmetic := function( R, dim ) 526 local r, i, intlist, j, vec1, vec2, mat1, mat2, row; 527 528 r:= Random( R ); 529 if IsGeneralizedRowVector( r ) then 530 531 # tests of kind 1. 532 for i in [ 1 .. ARITH_LST_REPS ] do 533 RunTest( ZeroTest, Random( R ) ); 534 RunTest( AdditiveInverseTest, Random( R ) ); 535 RunTest( AdditionTest, Random( R ), Random( R ) ); 536 od; 537 538 # tests of kind 2. 539 for i in [ 1 .. ARITH_LST_REPS ] do 540 RunTest( AdditionTest, Random( R ), [] ); 541 RunTest( AdditionTest, [], Random( R ) ); 542 r:= Random( R ); 543 intlist:= List( [ 1 .. Length( r ) + Random( -1, 1 ) ], 544 x -> Random( Integers ) ); 545 for j in [ 1 .. Int( Length( r ) / 3 ) ] do 546 Unbind( intlist[ Random( 1, Length( intlist ) ) ] ); 547 od; 548 RunTest( AdditionTest, r, intlist ); 549 RunTest( AdditionTest, intlist, r ); 550 od; 551 552 fi; 553 554 # tests of kind 3. 555 for i in [ 1 .. ARITH_LST_REPS ] do 556 557 vec1:= List( [ 1 .. dim ], x -> Random( R ) ); 558 vec2:= List( [ 1 .. dim ], x -> Random( R ) ); 559 560 RunTest( ZeroTest, vec1 ); 561 RunTest( AdditiveInverseTest, vec1 ); 562 RunTest( AdditionTest, vec1, Random( R ) ); 563 RunTest( AdditionTest, Random( R ), vec2 ); 564 RunTest( AdditionTest, vec1, vec2 ); 565 RunTest( AdditionTest, vec1, [] ); 566 RunTest( AdditionTest, [], vec2 ); 567 Unbind( vec1[ dim ] ); 568 RunTest( AdditionTest, vec1, vec2 ); 569 Unbind( vec2[ Random( 1, dim ) ] ); 570 RunTest( ZeroTest, vec2 ); 571 RunTest( AdditiveInverseTest, vec1 ); 572 RunTest( AdditiveInverseTest, vec2 ); 573 RunTest( AdditionTest, vec1, vec2 ); 574 Unbind( vec1[ Random( 1, dim ) ] ); 575 RunTest( AdditionTest, vec1, vec2 ); 576 577 mat1:= RandomSquareArray( dim, R ); 578 mat2:= RandomSquareArray( dim, R ); 579 580 RunTest( ZeroTest, mat1 ); 581 RunTest( AdditiveInverseTest, mat1 ); 582 RunTest( TransposedMatTest, mat1 ); 583 RunTest( AdditionTest, mat1, Random( R ) ); 584 RunTest( AdditionTest, Random( R ), mat2 ); 585 RunTest( AdditionTest, vec1, mat2 ); 586 RunTest( AdditionTest, mat1, vec2 ); 587 RunTest( AdditionTest, mat1, mat2 ); 588 RunTest( AdditionTest, mat1, [] ); 589 RunTest( AdditionTest, [], mat2 ); 590 Unbind( mat1[ dim ] ); 591 row:= mat1[ Random( 1, dim-1 ) ]; 592 if not IsLockedRepresentationVector( row ) then 593 Unbind( row[ Random( 1, dim ) ] ); 594 fi; 595 RunTest( AdditionTest, mat1, mat2 ); 596 Unbind( mat2[ Random( 1, dim ) ] ); 597 RunTest( ZeroTest, mat2 ); 598 RunTest( AdditiveInverseTest, mat1 ); 599 RunTest( AdditiveInverseTest, mat2 ); 600 RunTest( TransposedMatTest, mat2 ); 601 RunTest( AdditionTest, mat1, mat2 ); 602 Unbind( mat1[ Random( 1, dim ) ] ); 603 RunTest( AdditionTest, mat1, mat2 ); 604 605 od; 606end;; 607 608############################################################################# 609## 610#F TestOfMultiplicativeListArithmetic( <R>, <dim> ) 611## 612## For a ring or list of ring elements <R> (such that `Random( <R> )' 613## returns an element in <R> and such that not all elements in <R> are 614## zero), 615## `TestOfMultiplicativeListArithmetic' performs the following tests of 616## multiplicative arithmetic operations. 617## \beginlist 618## \item{1.} 619## If the elements of <R> are in `IsMultiplicativeGeneralizedRowVector' 620## then it is checked whether `One', `Inverse', and `\*' 621## obey the definitions. 622## \item{2.} 623## If the elements of <R> are in `IsMultiplicativeGeneralizedRowVector' 624## then it is checked whether the product of elements in <R> and 625## (non-dense) plain lists of integers obeys the definitions. 626## (Note that contrary to the additive case, we need not chack the 627## special case of a multiplication with an empty list.) 628## \item{3.} 629## Check `One' and `Inverse' for nested plain lists of elements 630## in <R>, and `\*' for elements in <R> and nested plain lists of 631## elements in <R>. 632## \endlist 633## 634TestOfMultiplicativeListArithmetic := function( R, dim ) 635 local r, i, intlist, j, vec1, vec2, mat1, mat2, row; 636 637 r:= Random( R ); 638 if IsMultiplicativeGeneralizedRowVector( r ) then 639 640 # tests of kind 1. 641 for i in [ 1 .. ARITH_LST_REPS ] do 642 RunTest( OneTest, Random( R ) ); 643 RunTest( InverseTest, Random( R ) ); 644 RunTest( MultiplicationTest, Random( R ), Random( R ) ); 645 od; 646 647 # tests of kind 2. 648 for i in [ 1 .. ARITH_LST_REPS ] do 649 r:= Random( R ); 650 intlist:= List( [ 1 .. Length( r ) + Random( -1, 1 ) ], 651 x -> Random( Integers ) ); 652 for j in [ 1 .. Int( Length( r ) / 3 ) ] do 653 Unbind( intlist[ Random( 1, Length( intlist ) ) ] ); 654 od; 655 RunTest( MultiplicationTest, r, intlist ); 656 RunTest( MultiplicationTest, intlist, r ); 657 od; 658 659 fi; 660 661 # tests of kind 3. 662 for i in [ 1 .. ARITH_LST_REPS ] do 663 664 vec1:= List( [ 1 .. dim ], x -> Random( R ) ); 665 vec2:= List( [ 1 .. dim ], x -> Random( R ) ); 666 667 RunTest( OneTest, vec1 ); 668 RunTest( InverseTest, vec1 ); 669 RunTest( MultiplicationTest, vec1, Random( R ) ); 670 RunTest( MultiplicationTest, Random( R ), vec2 ); 671 RunTest( MultiplicationTest, vec1, vec2 ); 672 Unbind( vec1[ dim ] ); 673 RunTest( MultiplicationTest, vec1, vec2 ); 674 Unbind( vec2[ Random( 1, dim ) ] ); 675 RunTest( OneTest, vec2 ); 676 RunTest( InverseTest, vec1 ); 677 RunTest( InverseTest, vec2 ); 678 RunTest( MultiplicationTest, vec1, vec2 ); 679 Unbind( vec1[ Random( 1, dim ) ] ); 680 RunTest( MultiplicationTest, vec1, vec2 ); 681 682 mat1:= RandomSquareArray( dim, R ); 683 mat2:= RandomSquareArray( dim, R ); 684 685 RunTest( OneTest, mat1 ); 686 RunTest( InverseTest, mat1 ); 687 RunTest( MultiplicationTest, mat1, Random( R ) ); 688 RunTest( MultiplicationTest, Random( R ), mat2 ); 689 RunTest( MultiplicationTest, vec1, mat2 ); 690 RunTest( MultiplicationTest, mat1, vec2 ); 691 RunTest( MultiplicationTest, mat1, mat2 ); 692 Unbind( mat1[ dim ] ); 693 row:= mat1[ Random( 1, dim-1 ) ]; 694 if not IsLockedRepresentationVector( row ) then 695 Unbind( row[ Random( 1, dim ) ] ); 696 fi; 697 RunTest( MultiplicationTest, vec1, mat2 ); 698 RunTest( MultiplicationTest, mat1, vec2 ); 699 RunTest( MultiplicationTest, mat1, mat2 ); 700 Unbind( mat2[ Random( 1, dim ) ] ); 701 RunTest( OneTest, mat2 ); 702 RunTest( InverseTest, mat1 ); 703 RunTest( InverseTest, mat2 ); 704 RunTest( MultiplicationTest, mat1, mat2 ); 705 Unbind( mat1[ Random( 1, dim ) ] ); 706 RunTest( MultiplicationTest, mat1, mat2 ); 707 708 od; 709end;; 710 711############################################################################# 712## 713#F TestOfListArithmetic( <R>, <dimlist> ) 714## 715TestOfListArithmetic := function( R, dimlist ) 716 local n, len, bools, i; 717 718 len:= 100; 719 bools:= [ true, false ]; 720 721 for n in dimlist do 722 TestOfAdditiveListArithmetic( R, n ); 723 TestOfMultiplicativeListArithmetic( R, n ); 724 R:= List( [ 1 .. len ], x -> Random( R ) ); 725 if IsMutable( R[1] ) and not ForAll( R, IsZero ) then 726 for i in [ 1 .. len ] do 727 if Random( bools ) then 728 R[i]:= Immutable( R[i] ); 729 fi; 730 od; 731 TestOfAdditiveListArithmetic( R, n ); 732 TestOfMultiplicativeListArithmetic( R, n ); 733 fi; 734 od; 735end;; 736