or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

distributions.mdindex.mdmatrices.mdtesting.mdvectors.md

testing.mddocs/

0

# Testing Utilities

1

2

Numerical testing utilities with tolerance-based comparisons for vectors, matrices, and doubles. Essential for testing numerical algorithms where exact equality is impractical due to floating-point precision.

3

4

## Capabilities

5

6

### Double Comparison Utilities

7

8

Enhanced comparison operators for double values with absolute and relative tolerance support.

9

10

```scala { .api }

11

object TestingUtils {

12

/** Helper case class for double comparisons */

13

case class CompareDoubleRightSide(

14

fun: (Double, Double, Double) => Boolean,

15

y: Double,

16

eps: Double,

17

method: String

18

)

19

20

/**

21

* Implicit class adding tolerance-based comparison operators to Double values

22

*/

23

implicit class DoubleWithAlmostEquals(val x: Double) {

24

/** Returns true if values are within tolerance */

25

def ~=(r: CompareDoubleRightSide): Boolean

26

27

/** Returns true if values are NOT within tolerance */

28

def !~=(r: CompareDoubleRightSide): Boolean

29

30

/** Throws exception if values are NOT within tolerance, otherwise returns true */

31

def ~==(r: CompareDoubleRightSide): Boolean

32

33

/** Throws exception if values ARE within tolerance, otherwise returns true */

34

def !~==(r: CompareDoubleRightSide): Boolean

35

36

/** Creates absolute tolerance comparison */

37

def absTol(eps: Double): CompareDoubleRightSide

38

39

/** Creates relative tolerance comparison */

40

def relTol(eps: Double): CompareDoubleRightSide

41

}

42

43

/** Message constants */

44

val ABS_TOL_MSG: String = " using absolute tolerance"

45

val REL_TOL_MSG: String = " using relative tolerance"

46

}

47

```

48

49

**Usage Examples:**

50

51

```scala

52

import org.apache.spark.ml.util.TestingUtils._

53

54

val x = 1.0000001

55

val y = 1.0000002

56

57

// Absolute tolerance comparison

58

val closeEnough = x ~= y absTol 1e-6

59

println(s"Close enough with absolute tolerance: $closeEnough") // true

60

61

val tooFar = x ~= y absTol 1e-8

62

println(s"Close enough with stricter tolerance: $tooFar") // false

63

64

// Relative tolerance comparison

65

val relativelyClose = x ~= y relTol 1e-6

66

println(s"Relatively close: $relativelyClose") // true

67

68

// Assertion-style comparisons (throw exceptions on failure)

69

try {

70

x ~== y absTol 1e-6 // Passes

71

println("Absolute tolerance assertion passed")

72

} catch {

73

case e: org.scalatest.exceptions.TestFailedException =>

74

println(s"Assertion failed: ${e.getMessage}")

75

}

76

77

try {

78

x ~== y absTol 1e-8 // Fails and throws exception

79

} catch {

80

case e: org.scalatest.exceptions.TestFailedException =>

81

println(s"Strict assertion failed: ${e.getMessage}")

82

}

83

84

// Negation comparisons

85

val notClose = x !~= y absTol 1e-8

86

println(s"Not close with strict tolerance: $notClose") // true

87

```

88

89

### Vector Comparison Utilities

90

91

Tolerance-based comparisons for Vector objects, comparing element-wise with specified tolerance.

92

93

```scala { .api }

94

object TestingUtils {

95

/** Helper case class for vector comparisons */

96

case class CompareVectorRightSide(

97

fun: (Vector, Vector, Double) => Boolean,

98

y: Vector,

99

eps: Double,

100

method: String

101

)

102

103

/**

104

* Implicit class adding tolerance-based comparison operators to Vector values

105

*/

106

implicit class VectorWithAlmostEquals(val x: Vector) {

107

/** Returns true if all vector elements are within tolerance */

108

def ~=(r: CompareVectorRightSide): Boolean

109

110

/** Returns true if any vector elements are NOT within tolerance */

111

def !~=(r: CompareVectorRightSide): Boolean

112

113

/** Throws exception if any elements are NOT within tolerance, otherwise returns true */

114

def ~==(r: CompareVectorRightSide): Boolean

115

116

/** Throws exception if all elements ARE within tolerance, otherwise returns true */

117

def !~==(r: CompareVectorRightSide): Boolean

118

119

/** Creates absolute tolerance comparison for vectors */

120

def absTol(eps: Double): CompareVectorRightSide

121

122

/** Creates relative tolerance comparison for vectors */

123

def relTol(eps: Double): CompareVectorRightSide

124

}

125

}

126

```

127

128

**Usage Examples:**

129

130

```scala

131

import org.apache.spark.ml.linalg.Vectors

132

import org.apache.spark.ml.util.TestingUtils._

133

134

val v1 = Vectors.dense(1.0, 2.0, 3.0)

135

val v2 = Vectors.dense(1.000001, 1.999999, 3.000001)

136

val v3 = Vectors.dense(1.1, 2.1, 3.1)

137

138

// Absolute tolerance comparison

139

val closeVectors = v1 ~= v2 absTol 1e-5

140

println(s"Vectors close with absolute tolerance: $closeVectors") // true

141

142

val farVectors = v1 ~= v3 absTol 1e-5

143

println(s"Vectors close with strict tolerance: $farVectors") // false

144

145

// Relative tolerance comparison

146

val relativelyCloseVectors = v1 ~= v2 relTol 1e-5

147

println(s"Vectors relatively close: $relativelyCloseVectors") // true

148

149

// Assertion-style comparisons

150

try {

151

v1 ~== v2 absTol 1e-5 // Passes

152

println("Vector absolute tolerance assertion passed")

153

} catch {

154

case e: org.scalatest.exceptions.TestFailedException =>

155

println(s"Vector assertion failed: ${e.getMessage}")

156

}

157

158

// Working with sparse vectors

159

val sparse1 = Vectors.sparse(5, Array(0, 2, 4), Array(1.0, 3.0, 5.0))

160

val sparse2 = Vectors.sparse(5, Array(0, 2, 4), Array(1.000001, 2.999999, 5.000001))

161

162

val sparsesClose = sparse1 ~= sparse2 absTol 1e-5

163

println(s"Sparse vectors close: $sparsesClose") // true

164

165

// Mixed dense/sparse comparison

166

val dense = Vectors.dense(1.0, 0.0, 3.0, 0.0, 5.0)

167

val mixedClose = dense ~= sparse1 absTol 1e-10

168

println(s"Dense and sparse vectors close: $mixedClose") // true

169

```

170

171

### Matrix Comparison Utilities

172

173

Tolerance-based comparisons for Matrix objects, comparing element-wise with specified tolerance.

174

175

```scala { .api }

176

object TestingUtils {

177

/** Helper case class for matrix comparisons */

178

case class CompareMatrixRightSide(

179

fun: (Matrix, Matrix, Double) => Boolean,

180

y: Matrix,

181

eps: Double,

182

method: String

183

)

184

185

/**

186

* Implicit class adding tolerance-based comparison operators to Matrix values

187

*/

188

implicit class MatrixWithAlmostEquals(val x: Matrix) {

189

/** Returns true if all matrix elements are within tolerance */

190

def ~=(r: CompareMatrixRightSide): Boolean

191

192

/** Returns true if any matrix elements are NOT within tolerance */

193

def !~=(r: CompareMatrixRightSide): Boolean

194

195

/** Throws exception if any elements are NOT within tolerance, otherwise returns true */

196

def ~==(r: CompareMatrixRightSide): Boolean

197

198

/** Throws exception if all elements ARE within tolerance, otherwise returns true */

199

def !~==(r: CompareMatrixRightSide): Boolean

200

201

/** Creates absolute tolerance comparison for matrices */

202

def absTol(eps: Double): CompareMatrixRightSide

203

204

/** Creates relative tolerance comparison for matrices */

205

def relTol(eps: Double): CompareMatrixRightSide

206

}

207

}

208

```

209

210

**Usage Examples:**

211

212

```scala

213

import org.apache.spark.ml.linalg.Matrices

214

import org.apache.spark.ml.util.TestingUtils._

215

216

val m1 = Matrices.dense(2, 2, Array(1.0, 2.0, 3.0, 4.0))

217

val m2 = Matrices.dense(2, 2, Array(1.000001, 1.999999, 3.000001, 3.999999))

218

val m3 = Matrices.dense(2, 2, Array(1.1, 2.1, 3.1, 4.1))

219

220

// Absolute tolerance comparison

221

val closeMatrices = m1 ~= m2 absTol 1e-5

222

println(s"Matrices close with absolute tolerance: $closeMatrices") // true

223

224

val farMatrices = m1 ~= m3 absTol 1e-5

225

println(s"Matrices close with strict tolerance: $farMatrices") // false

226

227

// Relative tolerance comparison

228

val relativelyCloseMatrices = m1 ~= m2 relTol 1e-5

229

println(s"Matrices relatively close: $relativelyCloseMatrices") // true

230

231

// Assertion-style comparisons

232

try {

233

m1 ~== m2 absTol 1e-5 // Passes

234

println("Matrix absolute tolerance assertion passed")

235

} catch {

236

case e: org.scalatest.exceptions.TestFailedException =>

237

println(s"Matrix assertion failed: ${e.getMessage}")

238

}

239

240

// Working with sparse matrices

241

val sparse1 = Matrices.sparse(3, 3, Array(0, 1, 2, 3), Array(0, 1, 2), Array(1.0, 2.0, 3.0))

242

val sparse2 = Matrices.sparse(3, 3, Array(0, 1, 2, 3), Array(0, 1, 2), Array(1.000001, 1.999999, 3.000001))

243

244

val sparsesClose = sparse1 ~= sparse2 absTol 1e-5

245

println(s"Sparse matrices close: $sparsesClose") // true

246

247

// Mixed dense/sparse comparison

248

val denseEquiv = Matrices.dense(3, 3, Array(1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0))

249

val mixedClose = denseEquiv ~= sparse1 absTol 1e-10

250

println(s"Dense and sparse matrices close: $mixedClose") // true

251

```

252

253

### Practical Testing Examples

254

255

#### Testing Vector Operations

256

257

```scala

258

import org.apache.spark.ml.linalg.Vectors

259

import org.apache.spark.ml.util.TestingUtils._

260

261

def testVectorOperations(): Unit = {

262

val v1 = Vectors.dense(1.0, 2.0, 3.0)

263

val v2 = Vectors.dense(4.0, 5.0, 6.0)

264

val expected = 32.0 // 1*4 + 2*5 + 3*6

265

266

// Calculate dot product using vector operations

267

val result = v1.toArray.zip(v2.toArray).map{ case (a, b) => a * b }.sum

268

269

// Test with tolerance

270

assert(result ~== expected absTol 1e-10)

271

println("Vector dot product test passed")

272

}

273

274

def testVectorNorms(): Unit = {

275

val vector = Vectors.dense(3.0, 4.0)

276

val expectedL2Norm = 5.0 // sqrt(3^2 + 4^2)

277

278

val l2Norm = Vectors.norm(vector, 2.0)

279

280

// Test with tolerance

281

assert(l2Norm ~== expectedL2Norm absTol 1e-10)

282

println("Vector norm test passed")

283

}

284

285

testVectorOperations()

286

testVectorNorms()

287

```

288

289

#### Testing Matrix Operations

290

291

```scala

292

import org.apache.spark.ml.linalg.Matrices

293

import org.apache.spark.ml.util.TestingUtils._

294

295

def testMatrixMultiplication(): Unit = {

296

val A = Matrices.dense(2, 2, Array(1.0, 2.0, 3.0, 4.0)) // [[1,3],[2,4]]

297

val B = Matrices.dense(2, 2, Array(5.0, 6.0, 7.0, 8.0)) // [[5,7],[6,8]]

298

val expected = Matrices.dense(2, 2, Array(19.0, 22.0, 43.0, 50.0))

299

300

val result = A.multiply(B)

301

302

// Test with tolerance

303

assert(result ~== expected absTol 1e-10)

304

println("Matrix multiplication test passed")

305

}

306

307

testMatrixMultiplication()

308

```

309

310

### Advanced Tolerance Considerations

311

312

#### Absolute vs Relative Tolerance

313

314

```scala

315

import org.apache.spark.ml.util.TestingUtils._

316

317

// For values near zero, use absolute tolerance

318

val nearZero1 = 1e-10

319

val nearZero2 = 2e-10

320

assert(nearZero1 ~== nearZero2 absTol 1e-9) // Good

321

// nearZero1 ~== nearZero2 relTol 1e-9 // Would throw exception - relative tolerance meaningless

322

323

// For larger values, relative tolerance is often better

324

val large1 = 1e6

325

val large2 = 1.000001e6

326

assert(large1 ~== large2 relTol 1e-5) // Good

327

// large1 ~== large2 absTol 1e-5 // Would fail - absolute difference is 1.0

328

```

329

330

#### NaN Handling

331

332

```scala

333

import org.apache.spark.ml.util.TestingUtils._

334

335

val nan1 = Double.NaN

336

val nan2 = Double.NaN

337

338

// NaN values are considered equal in tolerance comparisons

339

assert(nan1 ~== nan2 absTol 1e-10) // Passes

340

assert(nan1 ~== nan2 relTol 1e-10) // Passes

341

342

println("NaN comparison tests passed")

343

```

344

345

## Types

346

347

```scala { .api }

348

// Helper case classes for comparison operations

349

case class CompareDoubleRightSide(

350

fun: (Double, Double, Double) => Boolean,

351

y: Double,

352

eps: Double,

353

method: String

354

)

355

356

case class CompareVectorRightSide(

357

fun: (Vector, Vector, Double) => Boolean,

358

y: Vector,

359

eps: Double,

360

method: String

361

)

362

363

case class CompareMatrixRightSide(

364

fun: (Matrix, Matrix, Double) => Boolean,

365

y: Matrix,

366

eps: Double,

367

method: String

368

)

369

370

// Implicit classes that add comparison operators

371

implicit class DoubleWithAlmostEquals(val x: Double)

372

implicit class VectorWithAlmostEquals(val x: Vector)

373

implicit class MatrixWithAlmostEquals(val x: Matrix)

374

```