or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/pypi-kiwisolver

A fast implementation of the Cassowary constraint solver

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/kiwisolver@1.4.x

To install, run

npx @tessl/cli install tessl/pypi-kiwisolver@1.4.0

0

# Kiwisolver

1

2

A fast implementation of the Cassowary constraint solver providing an efficient C++ implementation with hand-rolled Python bindings. Kiwisolver enables developers to solve linear constraint systems for GUI layout management, mathematical optimization problems, and user interface positioning with performance improvements of 10x to 500x over the original Cassowary solver.

3

4

## Package Information

5

6

- **Package Name**: kiwisolver

7

- **Language**: Python

8

- **Installation**: `pip install kiwisolver`

9

- **Python Version**: 3.10+

10

11

## Core Imports

12

13

```python

14

import kiwisolver

15

```

16

17

Common imports for constraint solving:

18

19

```python

20

from kiwisolver import Variable, Solver, Constraint, Expression, Term, strength

21

```

22

23

Exception handling imports:

24

25

```python

26

from kiwisolver import (

27

UnsatisfiableConstraint,

28

DuplicateConstraint,

29

UnknownConstraint,

30

DuplicateEditVariable,

31

UnknownEditVariable,

32

BadRequiredStrength

33

)

34

```

35

36

Type annotation imports:

37

38

```python

39

from typing import Any, Iterable, Tuple, Literal

40

```

41

42

## Basic Usage

43

44

```python

45

from kiwisolver import Variable, Solver, strength

46

47

# Create variables for a simple layout problem

48

left = Variable("left")

49

width = Variable("width")

50

right = Variable("right")

51

52

# Create solver and add constraints

53

solver = Solver()

54

55

# Basic relationship: left + width = right

56

solver.addConstraint(left + width == right)

57

58

# Set some values with different strengths

59

solver.addConstraint(left >= 0) # Required strength (default)

60

solver.addConstraint(width >= 100 | strength.strong) # Strong preference

61

solver.addConstraint(right <= 500 | strength.medium) # Medium preference

62

63

# Solve the system

64

solver.updateVariables()

65

66

print(f"Left: {left.value()}, Width: {width.value()}, Right: {right.value()}")

67

```

68

69

## Architecture

70

71

Kiwisolver implements the Cassowary constraint solving algorithm through a hierarchy of mathematical components:

72

73

- **Variables**: Named unknowns that can be solved for

74

- **Terms**: Products of variables and coefficients (`coefficient * variable`)

75

- **Expressions**: Sums of terms plus constants (`term1 + term2 + ... + constant`)

76

- **Constraints**: Relationships between expressions with operators (`==`, `>=`, `<=`) and strengths

77

- **Solver**: The main engine that maintains and solves constraint systems

78

- **Strength System**: Hierarchical priority system for conflicting constraints (required > strong > medium > weak)

79

80

This design enables natural mathematical syntax through operator overloading while providing fine-grained control over constraint priorities and conflict resolution.

81

82

## Capabilities

83

84

### Variable Management

85

86

Create and manage constraint variables with optional naming and context for debugging and identification.

87

88

```python { .api }

89

class Variable:

90

def __init__(self, name: str = "", context: Any = None) -> None:

91

"""Create a new constraint variable.

92

93

Args:

94

name: Optional name for debugging

95

context: Optional context object for application use

96

"""

97

98

def name(self) -> str:

99

"""Get the variable name."""

100

101

def setName(self, name: str) -> None:

102

"""Set the variable name."""

103

104

def value(self) -> float:

105

"""Get the current solved value of the variable."""

106

107

def context(self) -> Any:

108

"""Get the context object associated with the variable."""

109

110

def setContext(self, context: Any) -> None:

111

"""Set the context object associated with the variable."""

112

```

113

114

### Mathematical Expression Building

115

116

Build mathematical expressions using terms (coefficient * variable combinations) and expressions (sums of terms).

117

118

```python { .api }

119

class Term:

120

def __init__(self, variable: Variable, coefficient: int | float = 1.0) -> None:

121

"""Create a term representing coefficient * variable.

122

123

Args:

124

variable: The variable to multiply

125

coefficient: Multiplication factor (default 1.0)

126

"""

127

128

def coefficient(self) -> float:

129

"""Get the coefficient for the term."""

130

131

def variable(self) -> Variable:

132

"""Get the variable for the term."""

133

134

def value(self) -> float:

135

"""Get the current evaluated value (coefficient * variable.value())."""

136

137

class Expression:

138

def __init__(self, terms: Iterable[Term], constant: int | float = 0.0) -> None:

139

"""Create an expression as sum of terms plus constant.

140

141

Args:

142

terms: Collection of Term objects to sum

143

constant: Constant value to add (default 0.0)

144

"""

145

146

def constant(self) -> float:

147

"""Get the constant term."""

148

149

def terms(self) -> Tuple[Term, ...]:

150

"""Get the tuple of terms in the expression."""

151

152

def value(self) -> float:

153

"""Get the current evaluated value of the entire expression."""

154

```

155

156

### Constraint Creation and Management

157

158

Create constraints from expressions using comparison operators and manage constraint strengths for conflict resolution.

159

160

```python { .api }

161

class Constraint:

162

def __init__(

163

self,

164

expression: Expression,

165

op: Literal["==", "<=", ">="],

166

strength: float | Literal["weak", "medium", "strong", "required"] = "required"

167

) -> None:

168

"""Create a constraint from an expression.

169

170

Args:

171

expression: Mathematical expression for the constraint

172

op: Comparison operator ("==", "<=", or ">=")

173

strength: Constraint strength (default "required")

174

"""

175

176

def expression(self) -> Expression:

177

"""Get the expression object for the constraint."""

178

179

def op(self) -> Literal["==", "<=", ">="]:

180

"""Get the relational operator for the constraint."""

181

182

def strength(self) -> float:

183

"""Get the numeric strength value."""

184

185

def violated(self) -> bool:

186

"""Indicate if the constraint is violated in the current state of the solver."""

187

```

188

189

### Constraint Solving

190

191

Main solver engine for managing and solving constraint systems with support for dynamic constraint modification.

192

193

```python { .api }

194

class Solver:

195

def __init__(self) -> None:

196

"""Create a new constraint solver."""

197

198

def addConstraint(self, constraint: Constraint) -> None:

199

"""Add a constraint to the solver.

200

201

Raises:

202

DuplicateConstraint: If constraint already exists

203

UnsatisfiableConstraint: If constraint cannot be satisfied

204

"""

205

206

def removeConstraint(self, constraint: Constraint) -> None:

207

"""Remove a constraint from the solver.

208

209

Raises:

210

UnknownConstraint: If constraint doesn't exist

211

"""

212

213

def hasConstraint(self, constraint: Constraint) -> bool:

214

"""Check if solver contains a specific constraint."""

215

216

def addEditVariable(

217

self,

218

variable: Variable,

219

strength: float | Literal["weak", "medium", "strong", "required"]

220

) -> None:

221

"""Add a variable that can be dynamically modified.

222

223

Args:

224

variable: Variable to make editable

225

strength: Strength for edit operations

226

227

Raises:

228

DuplicateEditVariable: If variable already added as edit variable

229

BadRequiredStrength: If required strength used for edit variable

230

"""

231

232

def removeEditVariable(self, variable: Variable) -> None:

233

"""Remove an edit variable from the solver.

234

235

Raises:

236

UnknownEditVariable: If variable is not an edit variable

237

"""

238

239

def hasEditVariable(self, variable: Variable) -> bool:

240

"""Check if variable is registered as an edit variable."""

241

242

def suggestValue(self, variable: Variable, value: int | float) -> None:

243

"""Suggest a desired value for an edit variable.

244

245

Args:

246

variable: Edit variable to modify

247

value: Suggested value

248

249

Raises:

250

UnknownEditVariable: If variable is not an edit variable

251

"""

252

253

def updateVariables(self) -> None:

254

"""Solve the constraint system and update all variable values."""

255

256

def reset(self) -> None:

257

"""Reset solver to empty state, removing all constraints and edit variables."""

258

259

def dump(self) -> None:

260

"""Print solver internal state to stdout for debugging."""

261

262

def dumps(self) -> str:

263

"""Return solver internal state as string for debugging."""

264

```

265

266

### Strength Management

267

268

Hierarchical constraint strength system for resolving conflicts between competing constraints. The `strength` object is a singleton instance providing predefined strength values and custom strength creation.

269

270

```python { .api }

271

# Singleton strength instance - do not instantiate directly

272

strength: Strength

273

274

# Predefined strength values (properties)

275

strength.weak: float # Weakest constraint strength

276

strength.medium: float # Medium constraint strength

277

strength.strong: float # Strong constraint strength

278

strength.required: float # Required constraint strength (highest priority)

279

280

def strength.create(

281

a: int | float,

282

b: int | float,

283

c: int | float,

284

weight: int | float = 1.0

285

) -> float:

286

"""Create custom constraint strength.

287

288

Args:

289

a, b, c: Strength hierarchy components

290

weight: Additional weight factor (default: 1.0)

291

292

Returns:

293

Custom strength value

294

"""

295

```

296

297

### Version Information

298

299

Package and library version information for compatibility checking.

300

301

```python { .api }

302

__version__: str # Python package version

303

__kiwi_version__: str # Underlying C++ library version

304

```

305

306

## Exception Handling

307

308

Kiwisolver provides specific exceptions for different constraint solving errors:

309

310

```python { .api }

311

class BadRequiredStrength(Exception):

312

"""Raised when required strength is used inappropriately."""

313

314

class DuplicateConstraint(Exception):

315

"""Raised when adding a constraint that already exists."""

316

constraint: Constraint # The duplicate constraint

317

318

class DuplicateEditVariable(Exception):

319

"""Raised when adding an edit variable that already exists."""

320

edit_variable: Variable # The duplicate edit variable

321

322

class UnknownConstraint(Exception):

323

"""Raised when removing a constraint that doesn't exist."""

324

constraint: Constraint # The unknown constraint

325

326

class UnknownEditVariable(Exception):

327

"""Raised when operating on an edit variable that doesn't exist."""

328

edit_variable: Variable # The unknown edit variable

329

330

class UnsatisfiableConstraint(Exception):

331

"""Raised when constraints cannot be satisfied."""

332

constraint: Constraint # The constraint that caused the conflict

333

```

334

335

## Mathematical Operators

336

337

Variables, Terms, and Expressions support rich mathematical syntax through operator overloading:

338

339

**Arithmetic Operations:**

340

- `+`, `-`: Addition and subtraction between Variables, Terms, Expressions, and numbers (returns Expression)

341

- `*`, `/`: Multiplication and division with numeric coefficients (returns Term or Expression)

342

- `-x`: Negation (unary minus) - returns Term for Variable, Term/Expression for others

343

344

**Constraint Creation:**

345

- `==`: Equality constraint (`expression == value`) - returns Constraint

346

- `>=`: Greater-than-or-equal constraint (`expression >= value`) - returns Constraint

347

- `<=`: Less-than-or-equal constraint (`expression <= value`) - returns Constraint

348

- **Unsupported**: `!=`, `>`, `<` operators will raise exceptions

349

350

**Strength Modification:**

351

- `|`: Apply strength to constraint (`constraint | strength.medium`)

352

353

## Usage Examples

354

355

### Simple Layout Problem

356

357

```python

358

from kiwisolver import Variable, Solver, strength

359

360

# Create variables for a horizontal layout

361

x1, w1, x2, w2 = Variable("x1"), Variable("w1"), Variable("x2"), Variable("w2")

362

363

solver = Solver()

364

365

# Define relationships

366

solver.addConstraint(x1 + w1 <= x2) # Widget 1 before widget 2

367

solver.addConstraint(x1 >= 0) # Left boundary

368

solver.addConstraint(x2 + w2 <= 800) # Right boundary

369

solver.addConstraint(w1 >= 100 | strength.strong) # Preferred width

370

solver.addConstraint(w2 >= 100 | strength.strong) # Preferred width

371

372

solver.updateVariables()

373

print(f"Widget 1: x={x1.value()}, w={w1.value()}")

374

print(f"Widget 2: x={x2.value()}, w={w2.value()}")

375

```

376

377

### Dynamic Value Suggestions

378

379

```python

380

from kiwisolver import Variable, Solver

381

382

# Create a resizable element

383

x, width = Variable("x"), Variable("width")

384

solver = Solver()

385

386

# Basic constraints

387

solver.addConstraint(x >= 0)

388

solver.addConstraint(x + width <= 1000)

389

solver.addConstraint(width >= 50)

390

391

# Make position editable

392

solver.addEditVariable(x, "medium")

393

solver.addEditVariable(width, "medium")

394

395

# Suggest new values dynamically

396

solver.suggestValue(x, 100)

397

solver.suggestValue(width, 200)

398

solver.updateVariables()

399

400

print(f"Position: {x.value()}, Width: {width.value()}")

401

402

# Update suggestions

403

solver.suggestValue(x, 300)

404

solver.updateVariables()

405

print(f"New position: {x.value()}, Width: {width.value()}")

406

```

407

408

### Complex Expression Building

409

410

```python

411

from kiwisolver import Variable, Term, Expression, Solver

412

413

# Create variables

414

a, b, c = Variable("a"), Variable("b"), Variable("c")

415

416

# Build complex expressions manually

417

term1 = Term(a, 2.0) # 2*a

418

term2 = Term(b, -1.5) # -1.5*b

419

expr = Expression([term1, term2], 10) # 2*a - 1.5*b + 10

420

421

# Or use operator overloading (equivalent)

422

expr2 = 2*a - 1.5*b + 10

423

424

solver = Solver()

425

solver.addConstraint(expr == c) # 2*a - 1.5*b + 10 = c

426

solver.addConstraint(a == 5)

427

solver.addConstraint(b == 2)

428

429

solver.updateVariables()

430

print(f"a={a.value()}, b={b.value()}, c={c.value()}")

431

print(f"Expression value: {expr.value()}")

432

```