or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

behavioral-analysis.mdcli-tools.mdcontract-system.mdindex.mdsymbolic-execution.md

behavioral-analysis.mddocs/

0

# Behavioral Analysis and Comparison

1

2

CrossHair provides sophisticated tools for analyzing and comparing the behavior of different function implementations. These capabilities enable developers to find behavioral differences, validate refactoring efforts, and generate comprehensive behavior descriptions.

3

4

## Capabilities

5

6

### Function Behavior Comparison

7

8

Compare the behavior of two function implementations to identify differences in outputs, exceptions, or side effects.

9

10

```python { .api }

11

def diff_behavior(fn1, fn2, *, sig=None, options=None):

12

"""

13

Compare behaviors of two functions.

14

15

Parameters:

16

- fn1: First function to compare

17

- fn2: Second function to compare

18

- sig: Optional signature specification for comparison

19

- options: Optional AnalysisOptions for controlling comparison

20

21

Returns:

22

Generator yielding BehaviorDiff instances describing differences

23

24

Uses symbolic execution to explore input spaces and find cases

25

where the two functions exhibit different behavior. Compares

26

return values, exception types, and execution characteristics.

27

"""

28

29

def diff_behavior_with_signature(fn1, fn2, sig, options):

30

"""

31

Compare behaviors with specific signature constraints.

32

33

Parameters:

34

- fn1: First function to compare

35

- fn2: Second function to compare

36

- sig: Signature object defining input constraints

37

- options: AnalysisOptions configuration

38

39

Returns:

40

Generator yielding detailed behavioral differences

41

42

Performs targeted comparison using a specific function signature,

43

enabling more focused analysis of particular input patterns.

44

"""

45

```

46

47

**Usage Examples:**

48

49

```python

50

from crosshair.diff_behavior import diff_behavior

51

52

def old_sort(items, reverse=False):

53

"""Original implementation"""

54

result = list(items)

55

result.sort(reverse=reverse)

56

return result

57

58

def new_sort(items, reverse=False):

59

"""New implementation with bug"""

60

result = list(items)

61

result.sort() # Bug: ignores reverse parameter

62

return result

63

64

# Find behavioral differences

65

for diff in diff_behavior(old_sort, new_sort):

66

print(f"Difference found:")

67

print(f" Input: {diff.args}")

68

print(f" old_sort: {diff.result1}")

69

print(f" new_sort: {diff.result2}")

70

print(f" Reason: {diff.message}")

71

```

72

73

### Behavior Description and Analysis

74

75

Generate comprehensive descriptions of function behavior for documentation and verification.

76

77

```python { .api }

78

def describe_behavior(fn, *, sig=None, options=None):

79

"""

80

Describe function behavior comprehensively.

81

82

Parameters:

83

- fn: Function to analyze

84

- sig: Optional signature specification

85

- options: Optional AnalysisOptions configuration

86

87

Returns:

88

Detailed behavior description including:

89

- Input/output relationships

90

- Exception conditions

91

- Edge case handling

92

- Performance characteristics

93

94

Performs exhaustive symbolic execution to characterize

95

the complete behavior space of a function.

96

"""

97

```

98

99

**Usage Example:**

100

101

```python

102

from crosshair.diff_behavior import describe_behavior

103

104

def calculate_discount(price, discount_percent, customer_type="standard"):

105

"""

106

Calculate discount for a purchase.

107

108

pre: price >= 0

109

pre: 0 <= discount_percent <= 100

110

post: 0 <= __return__ <= price

111

"""

112

if customer_type == "premium":

113

discount_percent *= 1.2

114

115

discount_amount = price * (discount_percent / 100)

116

return min(discount_amount, price)

117

118

# Generate behavior description

119

behavior = describe_behavior(calculate_discount)

120

print(behavior.summary)

121

print("Edge cases found:", behavior.edge_cases)

122

print("Exception conditions:", behavior.exception_conditions)

123

```

124

125

### Behavioral Difference Analysis

126

127

Detailed analysis of differences found between function implementations.

128

129

```python { .api }

130

class BehaviorDiff:

131

"""

132

Represents a difference between function behaviors.

133

134

Contains detailed information about inputs that cause different

135

behaviors, including return values, exceptions, and execution

136

characteristics.

137

"""

138

139

def __init__(self, args, result1, result2, message, exception_diff=None):

140

"""

141

Initialize behavior difference.

142

143

Parameters:

144

- args: Input arguments that cause the difference

145

- result1: Result from first function

146

- result2: Result from second function

147

- message: Human-readable description of difference

148

- exception_diff: Optional exception difference details

149

"""

150

151

@property

152

def args(self):

153

"""Input arguments that trigger the behavioral difference."""

154

155

@property

156

def result1(self):

157

"""Result from the first function."""

158

159

@property

160

def result2(self):

161

"""Result from the second function."""

162

163

@property

164

def message(self):

165

"""Human-readable description of the difference."""

166

167

@property

168

def exception_diff(self):

169

"""Details about exception-related differences."""

170

171

class Result:

172

"""

173

Result of behavior analysis containing outcomes and metadata.

174

175

Encapsulates the results of function execution during behavioral

176

analysis, including return values, exceptions, and execution context.

177

"""

178

179

def __init__(self, return_value=None, exception=None, execution_log=None):

180

"""

181

Initialize analysis result.

182

183

Parameters:

184

- return_value: Value returned by function (if any)

185

- exception: Exception raised by function (if any)

186

- execution_log: Optional log of execution steps

187

"""

188

```

189

190

**Advanced Comparison Example:**

191

192

```python

193

from crosshair.diff_behavior import diff_behavior, BehaviorDiff

194

195

def safe_divide(a, b):

196

"""Safe division with error handling"""

197

if b == 0:

198

return float('inf') if a > 0 else float('-inf') if a < 0 else float('nan')

199

return a / b

200

201

def unsafe_divide(a, b):

202

"""Unsafe division that raises exceptions"""

203

return a / b

204

205

# Compare with exception analysis

206

for diff in diff_behavior(safe_divide, unsafe_divide):

207

if diff.exception_diff:

208

print(f"Exception handling difference:")

209

print(f" Input: a={diff.args[0]}, b={diff.args[1]}")

210

print(f" safe_divide: returns {diff.result1}")

211

print(f" unsafe_divide: raises {diff.result2}")

212

```

213

214

### Exception Equivalence Configuration

215

216

Configure how exceptions are compared during behavioral analysis.

217

218

```python { .api }

219

class ExceptionEquivalenceType(enum.Enum):

220

"""

221

Types of exception equivalence for behavioral comparison.

222

223

Controls how strictly exceptions are compared when analyzing

224

behavioral differences between functions.

225

"""

226

227

SAME_TYPE = "same_type"

228

"""Consider exceptions equivalent if they have the same type."""

229

230

SAME_TYPE_AND_MESSAGE = "same_type_and_message"

231

"""Consider exceptions equivalent if type and message match."""

232

233

EXACT = "exact"

234

"""Consider exceptions equivalent only if completely identical."""

235

```

236

237

**Usage with Different Equivalence Types:**

238

239

```python

240

from crosshair.diff_behavior import diff_behavior, ExceptionEquivalenceType

241

from crosshair.options import AnalysisOptions

242

243

def func1(x):

244

if x < 0:

245

raise ValueError("Negative input")

246

return x * 2

247

248

def func2(x):

249

if x < 0:

250

raise ValueError("Input cannot be negative") # Different message

251

return x * 2

252

253

# Compare with different exception equivalence settings

254

options = AnalysisOptions()

255

256

# Strict comparison (different messages = different behavior)

257

options.exception_equivalence = ExceptionEquivalenceType.EXACT

258

strict_diffs = list(diff_behavior(func1, func2, options=options))

259

260

# Lenient comparison (same type = equivalent)

261

options.exception_equivalence = ExceptionEquivalenceType.SAME_TYPE

262

lenient_diffs = list(diff_behavior(func1, func2, options=options))

263

264

print(f"Strict comparison found {len(strict_diffs)} differences")

265

print(f"Lenient comparison found {len(lenient_diffs)} differences")

266

```

267

268

### Performance and Behavior Profiling

269

270

Analyze performance characteristics alongside behavioral properties.

271

272

```python { .api }

273

class ExecutionProfile:

274

"""

275

Profile of function execution including performance metrics.

276

277

Contains timing information, resource usage, and execution

278

path statistics gathered during symbolic execution.

279

"""

280

281

def __init__(self, execution_time=None, path_count=None, solver_calls=None):

282

"""

283

Initialize execution profile.

284

285

Parameters:

286

- execution_time: Time spent in symbolic execution

287

- path_count: Number of execution paths explored

288

- solver_calls: Number of SMT solver queries made

289

"""

290

```

291

292

**Performance-Aware Comparison:**

293

294

```python

295

def optimized_fibonacci(n, memo={}):

296

"""Optimized fibonacci with memoization"""

297

if n in memo:

298

return memo[n]

299

if n <= 1:

300

return n

301

memo[n] = optimized_fibonacci(n-1, memo) + optimized_fibonacci(n-2, memo)

302

return memo[n]

303

304

def naive_fibonacci(n):

305

"""Naive recursive fibonacci"""

306

if n <= 1:

307

return n

308

return naive_fibonacci(n-1) + naive_fibonacci(n-2)

309

310

# Compare behavior with performance implications

311

from crosshair.options import AnalysisOptions

312

313

options = AnalysisOptions(per_path_timeout=1.0) # Short timeout

314

315

# The analysis might find that both produce same results

316

# but optimized version completes within timeout while naive doesn't

317

for diff in diff_behavior(optimized_fibonacci, naive_fibonacci, options=options):

318

print(f"Performance difference: {diff.message}")

319

```

320

321

### Integration with Testing Frameworks

322

323

Generate behavioral tests based on discovered differences and edge cases.

324

325

**Generating Regression Tests:**

326

327

```python

328

from crosshair.diff_behavior import diff_behavior

329

330

def generate_regression_tests(old_func, new_func, test_name_prefix="test"):

331

"""Generate regression tests from behavioral differences"""

332

test_cases = []

333

334

for i, diff in enumerate(diff_behavior(old_func, new_func)):

335

test_code = f"""

336

def {test_name_prefix}_difference_{i}():

337

'''Test case for behavioral difference {i}'''

338

args = {diff.args}

339

340

# Expected behavior from old function

341

expected = {repr(diff.result1)}

342

343

# Actual behavior from new function

344

actual = new_func(*args)

345

346

assert actual == expected, f"Behavioral difference: {{actual}} != {{expected}}"

347

"""

348

test_cases.append(test_code)

349

350

return test_cases

351

352

# Generate tests for refactored function

353

test_cases = generate_regression_tests(original_implementation, refactored_implementation)

354

for test in test_cases:

355

print(test)

356

```

357

358

### Behavioral Invariant Discovery

359

360

Discover and verify behavioral invariants across function implementations.

361

362

```python

363

def discover_invariants(functions, input_generator):

364

"""

365

Discover behavioral invariants across multiple function implementations.

366

367

Parameters:

368

- functions: List of function implementations to compare

369

- input_generator: Generator providing test inputs

370

371

Returns:

372

List of discovered invariants that hold across all implementations

373

"""

374

invariants = []

375

376

for inputs in input_generator:

377

results = [f(*inputs) for f in functions]

378

379

# Check if all functions produce same result

380

if all(r == results[0] for r in results):

381

invariant = f"For input {inputs}, all functions return {results[0]}"

382

invariants.append(invariant)

383

384

return invariants

385

```

386

387

**Example Invariant Discovery:**

388

389

```python

390

def math_sqrt_wrapper(x):

391

"""Wrapper for math.sqrt"""

392

import math

393

return math.sqrt(x)

394

395

def newton_sqrt(x, precision=1e-10):

396

"""Newton's method square root"""

397

if x < 0:

398

raise ValueError("Cannot compute square root of negative number")

399

if x == 0:

400

return 0

401

402

guess = x / 2

403

while abs(guess * guess - x) > precision:

404

guess = (guess + x / guess) / 2

405

return guess

406

407

# Discover invariants between implementations

408

def input_gen():

409

for x in [0, 1, 4, 9, 16, 25, 100]:

410

yield (x,)

411

412

invariants = discover_invariants(

413

[math_sqrt_wrapper, newton_sqrt],

414

input_gen()

415

)

416

417

for invariant in invariants:

418

print(invariant)

419

```