From 46b45067de0ee902ab569e9cf5d0634289066a80 Mon Sep 17 00:00:00 2001 From: Paullo9 Date: Sat, 31 Oct 2026 11:12:56 +0100 Subject: [PATCH 1/5] feat: read Hall symbols, expand a Hall-only CIF with its group HallSymbol.operations reads a Hall space-group symbol into every operation of the group in the setting it states (centring, generators, default axes, screw digits, origin shift; exact arithmetic in twelfths). All 530 settings spglib 2.8.0 lists read to exactly the operation set of spglib.get_symmetry_from_database (7 388 operations). CIFImport now uses the Hall symbol (_space_group_name_Hall or _symmetry_space_group_name_Hall): - no operation loop: the cell is expanded with the Hall group (was refused as missing operations). pymatgen-core 2026.10.16 looks the Hall symbol up among Hermann-Mauguin names, finds none and builds P1 with a warning. - a loop, and the group named by Hall symbol alone: a loop with fewer distinct operations than the Hall group is refused (incompleteSymmetryOperationsForSymbol, naming the Hall symbol); it was admitted (rock salt listing its 48 point operations built 2 atoms of 8). - a Hall group smaller than the IT number or Hermann-Mauguin symbol beside it is refused like a short loop. - a loop, even an identity-only one, still wins over the symbol. CIFDocument gains declaredHallSymbol. Pins: tools/pins/cif-symmetry/hall-pins.py writes hall-symbol-pins.json (parity row P37). Done: Hall-only CIFs read and checked. Next: check a listed operation list against the cell metric, its closure and the declared crystal class. Co-Authored-By: Claude Opus 5.5 --- Sources/DiffractoCore/CIFImport.swift | 46 +++- Sources/DiffractoCore/HallSymbol.swift | 240 ++++++++++++++++++ .../Fixtures/hall-symbol-pins.json | 1 + .../DiffractoCoreTests/HallSymbolTests.swift | 122 +++++++++ Tests/Fixtures/README.md | 3 +- docs/parity.md | 9 +- tools/pins/cif-symmetry/hall-pins.py | 119 +++++++++ 7 files changed, 530 insertions(+), 10 deletions(-) create mode 100644 Sources/DiffractoCore/HallSymbol.swift create mode 100644 Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json create mode 100644 Tests/DiffractoCoreTests/HallSymbolTests.swift create mode 100644 tools/pins/cif-symmetry/hall-pins.py diff --git a/Sources/DiffractoCore/CIFImport.swift b/Sources/DiffractoCore/CIFImport.swift index b6ac915..b9a5fef 100644 --- a/Sources/DiffractoCore/CIFImport.swift +++ b/Sources/DiffractoCore/CIFImport.swift @@ -41,6 +41,8 @@ public enum CIFImportError: Error, Equatable, Sendable, CustomStringConvertible case incompleteSymmetryOperations(spaceGroupNumber: Int, declaredName: String?, listed: Int, required: Int) /// As ``incompleteSymmetryOperations(spaceGroupNumber:declaredName:listed:required:)`` for a file that names its group /// by Hermann–Mauguin symbol alone (no IT number): the order is read from the symbol (``requiredOperationCount(hermannMauguin:alphaDeg:betaDeg:gammaDeg:rightAngleToleranceDeg:rotationsDiagonal:)``). + /// A file that names its group by Hall symbol alone (no IT number, no readable Hermann–Mauguin symbol) is held to the + /// order of the group the Hall symbol states (``HallSymbol/operations(_:)``), and `symbol` is the Hall symbol. case incompleteSymmetryOperationsForSymbol(symbol: String, listed: Int, required: Int) /// A `data_` block that defines no structure carries a symmetry-operation loop while another block defines one. case symmetryOperationsOutsideStructure(blockNames: [String]) @@ -109,10 +111,12 @@ public struct CIFDocument: Sendable, Equatable { public let declaredSpaceGroupSymbol: String? /// The IT number the file states; nil when none. public let declaredSpaceGroupNumber: Int? + /// The Hall symbol the file states, as written; nil when none. + public let declaredHallSymbol: String? /// The coarsest rounding half-step over every written fractional coordinate (0 when all are exact). public let coarsestHalfStep: Double - /// Whether the file carried an expanding symmetry-operation loop (`structure.fileOperations`); the structure's - /// operations are detected from the expanded cell either way. + /// Whether the file carried expanding operations (`structure.fileOperations`): a symmetry-operation loop, or, with no + /// loop, a Hall symbol read to its group. The structure's operations are detected from the expanded cell either way. public let hadSymmetryOperations: Bool } @@ -194,6 +198,7 @@ public enum CIFImport { return CIFDocument(structure: structure, dataBlockName: parsed.dataBlockName, displayName: name, declaredSpaceGroupSymbol: parsed.spaceGroupSymbol, declaredSpaceGroupNumber: parsed.spaceGroupNumber, + declaredHallSymbol: parsed.hallSymbol, coarsestHalfStep: parsed.coarsestHalfStep, hadSymmetryOperations: parsed.operations != nil) } @@ -220,6 +225,7 @@ public enum CIFImport { var coarsestHalfStep: Double var spaceGroupNumber: Int? var spaceGroupSymbol: String? + var hallSymbol: String? } /// One asymmetric-unit site plus how precisely each of its coordinates was written: `halfStep` is the half-width @@ -390,9 +396,20 @@ public enum CIFImport { do { ops.append(try SymmetryOperation(xyz: raw, maximumMagnitude: policy.maximumOperationMagnitude)) } catch { throw .unsupportedSymmetryOperation(raw) } } + // A Hall symbol states the whole group in the file's own setting, so a file that names its group by Hall symbol + // and carries no loop is expanded with the symbol's operations (`HallSymbol`, exact against spglib's 530 + // settings). pymatgen means its symbol fallback to do this, but looks a Hall symbol up among Hermann–Mauguin + // names, finds none and expands as P1 with a warning (pymatgen-core 2026.10.16, `CifParser.get_symops`). + let fileListsOperations = haveSymmetryLoop && ops.contains(where: { !$0.isIdentity }) + let hallSymbol = declaredHall(cellValues) + let hallOperations = hallSymbol.flatMap { symbol -> [SymmetryOperation]? in try? HallSymbol.operations(symbol) } + // A loop, even one holding only the identity, is what the file lists and wins over the symbol (as in pymatgen). + let expandsWithHall = !haveSymmetryLoop && (hallOperations?.count ?? 0) > 1 + if expandsWithHall, let hallOperations { ops = hallOperations } + let sites: [AtomSite] let operations: [SymmetryOperation]? - if haveSymmetryLoop, ops.contains(where: { !$0.isIdentity }) { + if fileListsOperations || expandsWithHall { // A file that names its space group must list every operation of it (in the setting its cell is written // in). Fewer builds a smaller structure (rock salt without its F-centring is CsCl, still cubic m-3m). // The judgement of a monoclinic centred cell (conventional or primitive) also reads the listed rotations: @@ -401,6 +418,8 @@ public enum CIFImport { (0..<3).allSatisfy { r in (0..<3).allSatisfy { c in r == c || op.rotation[r, c] == 0 } } } let listed = SymmetryOperation.distinctCount(ops) + // A Hall group stands in for the loop here: a Hall symbol smaller than the IT number or Hermann–Mauguin + // symbol the file also states (a mistyped "-P 1" beside No. 225) is refused like a short loop. if let number = spaceGroupNumber, let required = requiredOperationCount( spaceGroup: number, alphaDeg: alpha, betaDeg: beta, gammaDeg: gamma, @@ -416,6 +435,12 @@ public enum CIFImport { rightAngleToleranceDeg: policy.rightAngleToleranceDeg, rotationsDiagonal: diagonal), listed < required { throw .incompleteSymmetryOperationsForSymbol(symbol: symbol, listed: listed, required: required) + } else if fileListsOperations, spaceGroupNumber == nil, + declaredHermannMauguin(cellValues).flatMap(hermannMauguinFacts) == nil, + let hallSymbol, let hallOperations, listed < hallOperations.count { + // Named by Hall symbol alone: the symbol's group, centring included, is the order the loop must reach. + throw .incompleteSymmetryOperationsForSymbol(symbol: hallSymbol, listed: listed, + required: hallOperations.count) } let lattice = UnitCell(a: a, b: b, c: c, alphaDeg: alpha, betaDeg: beta, gammaDeg: gamma).realLattice sites = expand(baseSites, using: ops, latReal: lattice, policy: policy) @@ -429,7 +454,7 @@ public enum CIFImport { // itself says they are — P1, or no space-group declaration at all. A file that declares a non-P1 group // and omits its operations is an asymmetric unit with no way to expand it. (py4DSTEM hands CIF parsing to // pymatgen, which can derive the operations from the symbol; this importer carries no space-group tables, - // so the honest alternative is refusing.) + // so the honest alternative is refusing. A readable Hall symbol needs no table and was used above.) if let declared = declaredNonP1SpaceGroup(cellValues) { throw .missingSymmetryOperations(spaceGroup: declared) } @@ -446,7 +471,8 @@ public enum CIFImport { dataBlockName: dataBlockName, a: a, b: b, c: c, alpha: alpha, beta: beta, gamma: gamma, sites: sites, operations: operations, coarsestHalfStep: coarsestHalfStep, - spaceGroupNumber: spaceGroupNumber, spaceGroupSymbol: declaredHermannMauguin(cellValues)) + spaceGroupNumber: spaceGroupNumber, spaceGroupSymbol: declaredHermannMauguin(cellValues), + hallSymbol: hallSymbol) } // MARK: - Tokenizer @@ -712,6 +738,16 @@ public enum CIFImport { return nil } + /// The Hall symbol the file states (`_space_group_name_Hall`, or the older `_symmetry_space_group_name_Hall`); nil when + /// none. + private static func declaredHall(_ cellValues: [String: String]) -> String? { + for tag in ["_space_group_name_hall", "_symmetry_space_group_name_hall"] { + if let raw = cellValues[tag]?.trimmingCharacters(in: .whitespaces), + !raw.isEmpty, raw != "?", raw != "." { return raw } + } + return nil + } + /// The space group the file itself declares, when that declaration is anything other than P1: a display name for /// the refusal, or nil when the file declares P1 or declares nothing (`?` and `.` count as absent). A declaration /// that exists but cannot be read is returned too: guessing P1 from an unreadable tag would be the silent diff --git a/Sources/DiffractoCore/HallSymbol.swift b/Sources/DiffractoCore/HallSymbol.swift new file mode 100644 index 0000000..6544f9b --- /dev/null +++ b/Sources/DiffractoCore/HallSymbol.swift @@ -0,0 +1,240 @@ +// +// HallSymbol.swift +// Role: the operations of a space group from its Hall symbol (Hall 1981, Acta Cryst. A37, 517; the explicit-origin +// notation `_space_group_name_Hall` carries in a CIF). The symbol states the lattice centring, the generators +// with their axes and translations, and an origin shift, so it fixes the group in the file's own setting with +// no table: the 530 settings spglib 2.8.0 lists are each read to exactly its operation set +// (`spglib.get_symmetry_from_database`, pinned by `tools/pins/cif-symmetry/hall-pins.py`). +// Arithmetic is exact: translations are kept in twelfths. +// + +import Foundation + +public enum HallSymbolError: Error, Equatable, Sendable, CustomStringConvertible { + /// The text is not a Hall symbol this reader understands; `reason` names the part that failed. + case unreadable(symbol: String, reason: String) + + public var description: String { + switch self { + case .unreadable(let symbol, let reason): + return "Could not read the Hall symbol \"\(symbol)\": \(reason)." + } + } +} + +/// The space group a Hall symbol states, in the setting it states. +public enum HallSymbol { + + /// Every operation of the group `symbol` states, centring translations included, each translation in [0, 1). The + /// first operation is the identity; the order is the generation order (deterministic, not sorted). + /// + /// The grammar is Hall's: an optional `-` (a centre of symmetry at the origin) and the lattice letter (P A B C I R S T + /// F), then one to four matrix symbols `[-]N[axis][translations]` (N in 1 2 3 4 6; axis x y z, `'` or `"` for a + /// two-fold on a face diagonal, `*` for the body diagonal; translations a b c n u v w d and screw digits), then an + /// optional origin shift `(i j k)` in twelfths. An axis left out takes Hall's default: z first, x for a two-fold + /// after a 2 or 4, `'` for a two-fold after a 3 or 6, `*` for a three-fold in third place. Lattice letters are read + /// in either case; everything else is case-sensitive, as Hall wrote it. + public static func operations(_ symbol: String) throws(HallSymbolError) -> [SymmetryOperation] { + try group(symbol).map { op in + SymmetryOperation(rotation: op.rotation, + translation: SIMD3(Double(op.twelfths.x), Double(op.twelfths.y), Double(op.twelfths.z)) / 12) + } + } + + // MARK: - Exact operations + + /// R p + t with t in twelfths, reduced mod 12. + struct ExactOperation: Hashable { + let rotation: IntegerMatrix + let twelfths: SIMD3 + + init(rotation: IntegerMatrix, twelfths: SIMD3) { + self.rotation = rotation + self.twelfths = SIMD3(((twelfths.x % 12) + 12) % 12, ((twelfths.y % 12) + 12) % 12, + ((twelfths.z % 12) + 12) % 12) + } + + static let identity = ExactOperation(rotation: .identity, twelfths: .zero) + + /// self after other: R₁R₂, R₁t₂ + t₁. + func composed(with other: ExactOperation) -> ExactOperation { + ExactOperation(rotation: rotation.multiplied(by: other.rotation), + twelfths: HallSymbol.apply(rotation, other.twelfths) &+ twelfths) + } + } + + static func apply(_ m: IntegerMatrix, _ v: SIMD3) -> SIMD3 { + SIMD3((m.rows[0] &* v).wrappedSum(), (m.rows[1] &* v).wrappedSum(), (m.rows[2] &* v).wrappedSum()) + } + + // MARK: - Tables (Hall 1981, tables 2 to 4) + + /// Lattice translations per letter, in twelfths, beyond the origin. + private static let centring: [Character: [SIMD3]] = [ + "P": [], "A": [SIMD3(0, 6, 6)], "B": [SIMD3(6, 0, 6)], "C": [SIMD3(6, 6, 0)], "I": [SIMD3(6, 6, 6)], + "R": [SIMD3(8, 4, 4), SIMD3(4, 8, 8)], "S": [SIMD3(4, 4, 8), SIMD3(8, 8, 4)], + "T": [SIMD3(4, 8, 4), SIMD3(8, 4, 8)], + "F": [SIMD3(0, 6, 6), SIMD3(6, 0, 6), SIMD3(6, 6, 0)], + ] + + /// Translation symbols, in twelfths. + private static let translationSymbols: [Character: SIMD3] = [ + "a": SIMD3(6, 0, 0), "b": SIMD3(0, 6, 0), "c": SIMD3(0, 0, 6), "n": SIMD3(6, 6, 6), + "u": SIMD3(3, 0, 0), "v": SIMD3(0, 3, 0), "w": SIMD3(0, 0, 3), "d": SIMD3(3, 3, 3), + ] + + /// The proper rotation of order `n` about a principal axis. + private static func principal(_ n: Int, axis: Character) -> IntegerMatrix? { + let z: IntegerMatrix + switch n { + case 1: return .identity + case 2: z = IntegerMatrix([-1, 0, 0], [0, -1, 0], [0, 0, 1]) + case 3: z = IntegerMatrix([0, -1, 0], [1, -1, 0], [0, 0, 1]) + case 4: z = IntegerMatrix([0, -1, 0], [1, 0, 0], [0, 0, 1]) + case 6: z = IntegerMatrix([1, -1, 0], [1, 0, 0], [0, 0, 1]) + default: return nil + } + // x and y by cyclic permutation of the axes: (x, y, z) -> (y, z, x) takes the z-axis matrix to the x-axis one. + func permuted(_ m: IntegerMatrix, _ p: [Int]) -> IntegerMatrix { + IntegerMatrix(rows: (0..<3).map { r in SIMD3((0..<3).map { c in m[p[r], p[c]] }) }) + } + switch axis { + case "z": return z + case "x": return permuted(z, [2, 0, 1]) + case "y": return permuted(z, [1, 2, 0]) + default: return nil + } + } + + /// The two-folds on face diagonals (`'` along b - a style, `"` along a + b style), relative to the preceding axis. + private static func diagonalTwoFold(_ kind: Character, preceding: Character) -> IntegerMatrix? { + switch (kind, preceding) { + case ("'", "z"): return IntegerMatrix([0, -1, 0], [-1, 0, 0], [0, 0, -1]) + case ("\"", "z"): return IntegerMatrix([0, 1, 0], [1, 0, 0], [0, 0, -1]) + case ("'", "x"): return IntegerMatrix([-1, 0, 0], [0, 0, -1], [0, -1, 0]) + case ("\"", "x"): return IntegerMatrix([-1, 0, 0], [0, 0, 1], [0, 1, 0]) + case ("'", "y"): return IntegerMatrix([0, 0, -1], [0, -1, 0], [-1, 0, 0]) + case ("\"", "y"): return IntegerMatrix([0, 0, 1], [0, -1, 0], [1, 0, 0]) + default: return nil + } + } + + /// The three-fold along the body diagonal. + private static let bodyDiagonalThreeFold = IntegerMatrix([0, 0, 1], [1, 0, 0], [0, 1, 0]) + + // MARK: - Reading + + /// The group as exact operations, the identity first. + static func group(_ symbol: String) throws(HallSymbolError) -> [ExactOperation] { + func fail(_ reason: String) -> HallSymbolError { .unreadable(symbol: symbol, reason: reason) } + + var text = symbol.trimmingCharacters(in: .whitespaces) + var shift = SIMD3.zero + if let open = text.firstIndex(of: "(") { + guard text.hasSuffix(")") else { throw fail("the origin shift is not closed by \")\"") } + let inner = text[text.index(after: open).. 0, !improper, chars.isEmpty { + throw fail("\"\(token)\" is a bare 1 after the first place (a Hermann–Mauguin symbol, not a Hall symbol?)") + } + var axis: Character? + if let c = chars.first, "xyz'\"*".contains(c) { axis = c; chars.removeFirst() } + if axis == nil { + switch (index, n) { + case (0, _): axis = "z" + case (1, 2) where previousOrder == 2 || previousOrder == 4: axis = "x" + case (1, 2) where previousOrder == 3 || previousOrder == 6: axis = "'" + case (2, 3): axis = "*" + case (_, 1): axis = "z" + default: throw fail("\"\(token)\" leaves out an axis Hall gives no default for") + } + } + guard let axis else { throw fail("\"\(token)\" has no axis") } + + let proper: IntegerMatrix? + switch axis { + case "x", "y", "z": proper = principal(n, axis: axis) + case "'", "\"": proper = n == 2 ? diagonalTwoFold(axis, preceding: previousAxis) : nil + default: proper = n == 3 ? bodyDiagonalThreeFold : nil + } + guard let proper else { throw fail("\"\(token)\" names an axis its rotation order cannot have") } + + var translation = SIMD3.zero + for c in chars { + if let t = translationSymbols[c] { + translation &+= t + } else if let k = c.wholeNumberValue, k >= 1, k < n, "xyz".contains(axis) { + let step = 12 * k / n + switch axis { + case "x": translation.x += step + case "y": translation.y += step + default: translation.z += step + } + } else { + throw fail("\"\(token)\" has a translation symbol \"\(c)\" that is not a b c n u v w d or a screw digit below \(n)") + } + } + generators.append(ExactOperation(rotation: improper ? proper.negated : proper, twelfths: translation)) + if "xyz".contains(axis) { previousAxis = axis } + previousOrder = n + } + + // The closure; no space group has more than 192 operations in any Hall setting. + var elements: [ExactOperation] = [.identity] + var seen: Set = [.identity] + var frontier = 0 + while frontier < elements.count { + let element = elements[frontier] + frontier += 1 + for generator in generators { + let product = generator.composed(with: element) + if seen.insert(product).inserted { + elements.append(product) + guard elements.count <= 192 else { throw fail("its generators do not close into a space group") } + } + } + } + + // The origin shift: the operation x -> R x + t seen from an origin moved by -v is x -> R x + t + (I - R) v. + guard shift != .zero else { return elements } + return elements.map { op in + ExactOperation(rotation: op.rotation, twelfths: op.twelfths &+ shift &- apply(op.rotation, shift)) + } + } +} diff --git a/Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json b/Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json new file mode 100644 index 0000000..5d3c788 --- /dev/null +++ b/Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json @@ -0,0 +1 @@ +{"spglib":"2.8.0","pymatgen-core":"2026.10.16","groups":[{"hall":1,"number":1,"symbol":"P 1","operations":["+000+000+000"]},{"hall":2,"number":2,"symbol":"-P 1","operations":["+000+000+000","-000-000-000"]},{"hall":3,"number":3,"symbol":"P 2y","operations":["+000+000+000","-000+000-000"]},{"hall":4,"number":3,"symbol":"P 2","operations":["+000+000+000","-000-000+000"]},{"hall":5,"number":3,"symbol":"P 2x","operations":["+000+000+000","+000-000-000"]},{"hall":6,"number":4,"symbol":"P 2yb","operations":["+000+000+000","-000+000-060"]},{"hall":7,"number":4,"symbol":"P 2c","operations":["+000+000+000","-000-000+006"]},{"hall":8,"number":4,"symbol":"P 2xa","operations":["+000+000+000","+000-000-600"]},{"hall":9,"number":5,"symbol":"C 2y","operations":["+000+000+000","+000+000+660","-000+000-000","-000+000-660"]},{"hall":10,"number":5,"symbol":"A 2y","operations":["+000+000+000","+000+000+066","-000+000-000","-000+000-066"]},{"hall":11,"number":5,"symbol":"I 2y","operations":["+000+000+000","+000+000+666","-000+000-000","-000+000-666"]},{"hall":12,"number":5,"symbol":"A 2","operations":["+000+000+000","+000+000+066","-000-000+000","-000-000+066"]},{"hall":13,"number":5,"symbol":"B 2","operations":["+000+000+000","+000+000+606","-000-000+000","-000-000+606"]},{"hall":14,"number":5,"symbol":"I 2","operations":["+000+000+000","+000+000+666","-000-000+000","-000-000+666"]},{"hall":15,"number":5,"symbol":"B 2x","operations":["+000+000+000","+000+000+606","+000-000-000","+000-000-606"]},{"hall":16,"number":5,"symbol":"C 2x","operations":["+000+000+000","+000+000+660","+000-000-000","+000-000-660"]},{"hall":17,"number":5,"symbol":"I 2x","operations":["+000+000+000","+000+000+666","+000-000-000","+000-000-666"]},{"hall":18,"number":6,"symbol":"P -2y","operations":["+000+000+000","+000-000+000"]},{"hall":19,"number":6,"symbol":"P -2","operations":["+000+000+000","+000+000-000"]},{"hall":20,"number":6,"symbol":"P -2x","operations":["+000+000+000","-000+000+000"]},{"hall":21,"number":7,"symbol":"P -2yc","operations":["+000+000+000","+000-000+006"]},{"hall":22,"number":7,"symbol":"P -2yac","operations":["+000+000+000","+000-000+606"]},{"hall":23,"number":7,"symbol":"P -2ya","operations":["+000+000+000","+000-000+600"]},{"hall":24,"number":7,"symbol":"P -2a","operations":["+000+000+000","+000+000-600"]},{"hall":25,"number":7,"symbol":"P -2ab","operations":["+000+000+000","+000+000-660"]},{"hall":26,"number":7,"symbol":"P -2b","operations":["+000+000+000","+000+000-060"]},{"hall":27,"number":7,"symbol":"P -2xb","operations":["+000+000+000","-000+000+060"]},{"hall":28,"number":7,"symbol":"P -2xbc","operations":["+000+000+000","-000+000+066"]},{"hall":29,"number":7,"symbol":"P -2xc","operations":["+000+000+000","-000+000+006"]},{"hall":30,"number":8,"symbol":"C -2y","operations":["+000+000+000","+000+000+660","+000-000+000","+000-000+660"]},{"hall":31,"number":8,"symbol":"A -2y","operations":["+000+000+000","+000+000+066","+000-000+000","+000-000+066"]},{"hall":32,"number":8,"symbol":"I -2y","operations":["+000+000+000","+000+000+666","+000-000+000","+000-000+666"]},{"hall":33,"number":8,"symbol":"A -2","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066"]},{"hall":34,"number":8,"symbol":"B -2","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606"]},{"hall":35,"number":8,"symbol":"I -2","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666"]},{"hall":36,"number":8,"symbol":"B -2x","operations":["+000+000+000","+000+000+606","-000+000+000","-000+000+606"]},{"hall":37,"number":8,"symbol":"C -2x","operations":["+000+000+000","+000+000+660","-000+000+000","-000+000+660"]},{"hall":38,"number":8,"symbol":"I -2x","operations":["+000+000+000","+000+000+666","-000+000+000","-000+000+666"]},{"hall":39,"number":9,"symbol":"C -2yc","operations":["+000+000+000","+000+000+660","+000-000+006","+000-000+666"]},{"hall":40,"number":9,"symbol":"A -2yab","operations":["+000+000+000","+000+000+066","+000-000+606","+000-000+660"]},{"hall":41,"number":9,"symbol":"I -2ya","operations":["+000+000+000","+000+000+666","+000-000+066","+000-000+600"]},{"hall":42,"number":9,"symbol":"A -2ya","operations":["+000+000+000","+000+000+066","+000-000+600","+000-000+666"]},{"hall":43,"number":9,"symbol":"C -2yac","operations":["+000+000+000","+000+000+660","+000-000+066","+000-000+606"]},{"hall":44,"number":9,"symbol":"I -2yc","operations":["+000+000+000","+000+000+666","+000-000+006","+000-000+660"]},{"hall":45,"number":9,"symbol":"A -2a","operations":["+000+000+000","+000+000+066","+000+000-600","+000+000-666"]},{"hall":46,"number":9,"symbol":"B -2ab","operations":["+000+000+000","+000+000+606","+000+000-066","+000+000-660"]},{"hall":47,"number":9,"symbol":"I -2b","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606"]},{"hall":48,"number":9,"symbol":"B -2b","operations":["+000+000+000","+000+000+606","+000+000-060","+000+000-666"]},{"hall":49,"number":9,"symbol":"A -2ab","operations":["+000+000+000","+000+000+066","+000+000-606","+000+000-660"]},{"hall":50,"number":9,"symbol":"I -2a","operations":["+000+000+000","+000+000+666","+000+000-066","+000+000-600"]},{"hall":51,"number":9,"symbol":"B -2xb","operations":["+000+000+000","+000+000+606","-000+000+060","-000+000+666"]},{"hall":52,"number":9,"symbol":"C -2xac","operations":["+000+000+000","+000+000+660","-000+000+066","-000+000+606"]},{"hall":53,"number":9,"symbol":"I -2xc","operations":["+000+000+000","+000+000+666","-000+000+006","-000+000+660"]},{"hall":54,"number":9,"symbol":"C -2xc","operations":["+000+000+000","+000+000+660","-000+000+006","-000+000+666"]},{"hall":55,"number":9,"symbol":"B -2xab","operations":["+000+000+000","+000+000+606","-000+000+066","-000+000+660"]},{"hall":56,"number":9,"symbol":"I -2xb","operations":["+000+000+000","+000+000+666","-000+000+060","-000+000+606"]},{"hall":57,"number":10,"symbol":"-P 2y","operations":["+000+000+000","+000-000+000","-000+000-000","-000-000-000"]},{"hall":58,"number":10,"symbol":"-P 2","operations":["+000+000+000","+000+000-000","-000-000+000","-000-000-000"]},{"hall":59,"number":10,"symbol":"-P 2x","operations":["+000+000+000","+000-000-000","-000+000+000","-000-000-000"]},{"hall":60,"number":11,"symbol":"-P 2yb","operations":["+000+000+000","+000-000+060","-000+000-060","-000-000-000"]},{"hall":61,"number":11,"symbol":"-P 2c","operations":["+000+000+000","+000+000-006","-000-000+006","-000-000-000"]},{"hall":62,"number":11,"symbol":"-P 2xa","operations":["+000+000+000","+000-000-600","-000+000+600","-000-000-000"]},{"hall":63,"number":12,"symbol":"-C 2y","operations":["+000+000+000","+000+000+660","+000-000+000","+000-000+660","-000+000-000","-000+000-660","-000-000-000","-000-000-660"]},{"hall":64,"number":12,"symbol":"-A 2y","operations":["+000+000+000","+000+000+066","+000-000+000","+000-000+066","-000+000-000","-000+000-066","-000-000-000","-000-000-066"]},{"hall":65,"number":12,"symbol":"-I 2y","operations":["+000+000+000","+000+000+666","+000-000+000","+000-000+666","-000+000-000","-000+000-666","-000-000-000","-000-000-666"]},{"hall":66,"number":12,"symbol":"-A 2","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066","-000-000+000","-000-000+066","-000-000-000","-000-000-066"]},{"hall":67,"number":12,"symbol":"-B 2","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606","-000-000+000","-000-000+606","-000-000-000","-000-000-606"]},{"hall":68,"number":12,"symbol":"-I 2","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","-000-000+000","-000-000+666","-000-000-000","-000-000-666"]},{"hall":69,"number":12,"symbol":"-B 2x","operations":["+000+000+000","+000+000+606","+000-000-000","+000-000-606","-000+000+000","-000+000+606","-000-000-000","-000-000-606"]},{"hall":70,"number":12,"symbol":"-C 2x","operations":["+000+000+000","+000+000+660","+000-000-000","+000-000-660","-000+000+000","-000+000+660","-000-000-000","-000-000-660"]},{"hall":71,"number":12,"symbol":"-I 2x","operations":["+000+000+000","+000+000+666","+000-000-000","+000-000-666","-000+000+000","-000+000+666","-000-000-000","-000-000-666"]},{"hall":72,"number":13,"symbol":"-P 2yc","operations":["+000+000+000","+000-000+006","-000+000-006","-000-000-000"]},{"hall":73,"number":13,"symbol":"-P 2yac","operations":["+000+000+000","+000-000+606","-000+000-606","-000-000-000"]},{"hall":74,"number":13,"symbol":"-P 2ya","operations":["+000+000+000","+000-000+600","-000+000-600","-000-000-000"]},{"hall":75,"number":13,"symbol":"-P 2a","operations":["+000+000+000","+000+000-600","-000-000+600","-000-000-000"]},{"hall":76,"number":13,"symbol":"-P 2ab","operations":["+000+000+000","+000+000-660","-000-000+660","-000-000-000"]},{"hall":77,"number":13,"symbol":"-P 2b","operations":["+000+000+000","+000+000-060","-000-000+060","-000-000-000"]},{"hall":78,"number":13,"symbol":"-P 2xb","operations":["+000+000+000","+000-000-060","-000+000+060","-000-000-000"]},{"hall":79,"number":13,"symbol":"-P 2xbc","operations":["+000+000+000","+000-000-066","-000+000+066","-000-000-000"]},{"hall":80,"number":13,"symbol":"-P 2xc","operations":["+000+000+000","+000-000-006","-000+000+006","-000-000-000"]},{"hall":81,"number":14,"symbol":"-P 2ybc","operations":["+000+000+000","+000-000+066","-000+000-066","-000-000-000"]},{"hall":82,"number":14,"symbol":"-P 2yn","operations":["+000+000+000","+000-000+666","-000+000-666","-000-000-000"]},{"hall":83,"number":14,"symbol":"-P 2yab","operations":["+000+000+000","+000-000+660","-000+000-660","-000-000-000"]},{"hall":84,"number":14,"symbol":"-P 2ac","operations":["+000+000+000","+000+000-606","-000-000+606","-000-000-000"]},{"hall":85,"number":14,"symbol":"-P 2n","operations":["+000+000+000","+000+000-666","-000-000+666","-000-000-000"]},{"hall":86,"number":14,"symbol":"-P 2bc","operations":["+000+000+000","+000+000-066","-000-000+066","-000-000-000"]},{"hall":87,"number":14,"symbol":"-P 2xab","operations":["+000+000+000","+000-000-660","-000+000+660","-000-000-000"]},{"hall":88,"number":14,"symbol":"-P 2xn","operations":["+000+000+000","+000-000-666","-000+000+666","-000-000-000"]},{"hall":89,"number":14,"symbol":"-P 2xac","operations":["+000+000+000","+000-000-606","-000+000+606","-000-000-000"]},{"hall":90,"number":15,"symbol":"-C 2yc","operations":["+000+000+000","+000+000+660","+000-000+006","+000-000+666","-000+000-006","-000+000-666","-000-000-000","-000-000-660"]},{"hall":91,"number":15,"symbol":"-A 2yab","operations":["+000+000+000","+000+000+066","+000-000+606","+000-000+660","-000+000-606","-000+000-660","-000-000-000","-000-000-066"]},{"hall":92,"number":15,"symbol":"-I 2ya","operations":["+000+000+000","+000+000+666","+000-000+066","+000-000+600","-000+000-066","-000+000-600","-000-000-000","-000-000-666"]},{"hall":93,"number":15,"symbol":"-A 2ya","operations":["+000+000+000","+000+000+066","+000-000+600","+000-000+666","-000+000-600","-000+000-666","-000-000-000","-000-000-066"]},{"hall":94,"number":15,"symbol":"-C 2yac","operations":["+000+000+000","+000+000+660","+000-000+066","+000-000+606","-000+000-066","-000+000-606","-000-000-000","-000-000-660"]},{"hall":95,"number":15,"symbol":"-I 2yc","operations":["+000+000+000","+000+000+666","+000-000+006","+000-000+660","-000+000-006","-000+000-660","-000-000-000","-000-000-666"]},{"hall":96,"number":15,"symbol":"-A 2a","operations":["+000+000+000","+000+000+066","+000+000-600","+000+000-666","-000-000+600","-000-000+666","-000-000-000","-000-000-066"]},{"hall":97,"number":15,"symbol":"-B 2ab","operations":["+000+000+000","+000+000+606","+000+000-066","+000+000-660","-000-000+066","-000-000+660","-000-000-000","-000-000-606"]},{"hall":98,"number":15,"symbol":"-I 2b","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","-000-000+060","-000-000+606","-000-000-000","-000-000-666"]},{"hall":99,"number":15,"symbol":"-B 2b","operations":["+000+000+000","+000+000+606","+000+000-060","+000+000-666","-000-000+060","-000-000+666","-000-000-000","-000-000-606"]},{"hall":100,"number":15,"symbol":"-A 2ab","operations":["+000+000+000","+000+000+066","+000+000-606","+000+000-660","-000-000+606","-000-000+660","-000-000-000","-000-000-066"]},{"hall":101,"number":15,"symbol":"-I 2a","operations":["+000+000+000","+000+000+666","+000+000-066","+000+000-600","-000-000+066","-000-000+600","-000-000-000","-000-000-666"]},{"hall":102,"number":15,"symbol":"-B 2xb","operations":["+000+000+000","+000+000+606","+000-000-060","+000-000-666","-000+000+060","-000+000+666","-000-000-000","-000-000-606"]},{"hall":103,"number":15,"symbol":"-C 2xac","operations":["+000+000+000","+000+000+660","+000-000-066","+000-000-606","-000+000+066","-000+000+606","-000-000-000","-000-000-660"]},{"hall":104,"number":15,"symbol":"-I 2xc","operations":["+000+000+000","+000+000+666","+000-000-006","+000-000-660","-000+000+006","-000+000+660","-000-000-000","-000-000-666"]},{"hall":105,"number":15,"symbol":"-C 2xc","operations":["+000+000+000","+000+000+660","+000-000-006","+000-000-666","-000+000+006","-000+000+666","-000-000-000","-000-000-660"]},{"hall":106,"number":15,"symbol":"-B 2xab","operations":["+000+000+000","+000+000+606","+000-000-066","+000-000-660","-000+000+066","-000+000+660","-000-000-000","-000-000-606"]},{"hall":107,"number":15,"symbol":"-I 2xb","operations":["+000+000+000","+000+000+666","+000-000-060","+000-000-606","-000+000+060","-000+000+606","-000-000-000","-000-000-666"]},{"hall":108,"number":16,"symbol":"P 2 2","operations":["+000+000+000","+000-000-000","-000+000-000","-000-000+000"]},{"hall":109,"number":17,"symbol":"P 2c 2","operations":["+000+000+000","+000-000-000","-000+000-006","-000-000+006"]},{"hall":110,"number":17,"symbol":"P 2a 2a","operations":["+000+000+000","+000-000-600","-000+000-000","-000-000+600"]},{"hall":111,"number":17,"symbol":"P 2 2b","operations":["+000+000+000","+000-000-060","-000+000-060","-000-000+000"]},{"hall":112,"number":18,"symbol":"P 2 2ab","operations":["+000+000+000","+000-000-660","-000+000-660","-000-000+000"]},{"hall":113,"number":18,"symbol":"P 2bc 2","operations":["+000+000+000","+000-000-000","-000+000-066","-000-000+066"]},{"hall":114,"number":18,"symbol":"P 2ac 2ac","operations":["+000+000+000","+000-000-606","-000+000-000","-000-000+606"]},{"hall":115,"number":19,"symbol":"P 2ac 2ab","operations":["+000+000+000","+000-000-660","-000+000-066","-000-000+606"]},{"hall":116,"number":20,"symbol":"C 2c 2","operations":["+000+000+000","+000+000+660","+000-000-000","+000-000-660","-000+000-006","-000+000-666","-000-000+006","-000-000+666"]},{"hall":117,"number":20,"symbol":"A 2a 2a","operations":["+000+000+000","+000+000+066","+000-000-600","+000-000-666","-000+000-000","-000+000-066","-000-000+600","-000-000+666"]},{"hall":118,"number":20,"symbol":"B 2 2b","operations":["+000+000+000","+000+000+606","+000-000-060","+000-000-666","-000+000-060","-000+000-666","-000-000+000","-000-000+606"]},{"hall":119,"number":21,"symbol":"C 2 2","operations":["+000+000+000","+000+000+660","+000-000-000","+000-000-660","-000+000-000","-000+000-660","-000-000+000","-000-000+660"]},{"hall":120,"number":21,"symbol":"A 2 2","operations":["+000+000+000","+000+000+066","+000-000-000","+000-000-066","-000+000-000","-000+000-066","-000-000+000","-000-000+066"]},{"hall":121,"number":21,"symbol":"B 2 2","operations":["+000+000+000","+000+000+606","+000-000-000","+000-000-606","-000+000-000","-000+000-606","-000-000+000","-000-000+606"]},{"hall":122,"number":22,"symbol":"F 2 2","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660"]},{"hall":123,"number":23,"symbol":"I 2 2","operations":["+000+000+000","+000+000+666","+000-000-000","+000-000-666","-000+000-000","-000+000-666","-000-000+000","-000-000+666"]},{"hall":124,"number":24,"symbol":"I 2b 2c","operations":["+000+000+000","+000+000+666","+000-000-006","+000-000-660","-000+000-066","-000+000-600","-000-000+060","-000-000+606"]},{"hall":125,"number":25,"symbol":"P 2 -2","operations":["+000+000+000","+000-000+000","-000+000+000","-000-000+000"]},{"hall":126,"number":25,"symbol":"P -2 2","operations":["+000+000+000","+000+000-000","+000-000+000","+000-000-000"]},{"hall":127,"number":25,"symbol":"P -2 -2","operations":["+000+000+000","+000+000-000","-000+000+000","-000+000-000"]},{"hall":128,"number":26,"symbol":"P 2c -2","operations":["+000+000+000","+000-000+006","-000+000+000","-000-000+006"]},{"hall":129,"number":26,"symbol":"P 2c -2c","operations":["+000+000+000","+000-000+000","-000+000+006","-000-000+006"]},{"hall":130,"number":26,"symbol":"P -2a 2a","operations":["+000+000+000","+000+000-600","+000-000+000","+000-000-600"]},{"hall":131,"number":26,"symbol":"P -2 2a","operations":["+000+000+000","+000+000-000","+000-000+600","+000-000-600"]},{"hall":132,"number":26,"symbol":"P -2 -2b","operations":["+000+000+000","+000+000-000","-000+000+060","-000+000-060"]},{"hall":133,"number":26,"symbol":"P -2b -2","operations":["+000+000+000","+000+000-060","-000+000+000","-000+000-060"]},{"hall":134,"number":27,"symbol":"P 2 -2c","operations":["+000+000+000","+000-000+006","-000+000+006","-000-000+000"]},{"hall":135,"number":27,"symbol":"P -2a 2","operations":["+000+000+000","+000+000-600","+000-000+600","+000-000-000"]},{"hall":136,"number":27,"symbol":"P -2b -2b","operations":["+000+000+000","+000+000-060","-000+000+060","-000+000-000"]},{"hall":137,"number":28,"symbol":"P 2 -2a","operations":["+000+000+000","+000-000+600","-000+000+600","-000-000+000"]},{"hall":138,"number":28,"symbol":"P 2 -2b","operations":["+000+000+000","+000-000+060","-000+000+060","-000-000+000"]},{"hall":139,"number":28,"symbol":"P -2b 2","operations":["+000+000+000","+000+000-060","+000-000+060","+000-000-000"]},{"hall":140,"number":28,"symbol":"P -2c 2","operations":["+000+000+000","+000+000-006","+000-000+006","+000-000-000"]},{"hall":141,"number":28,"symbol":"P -2c -2c","operations":["+000+000+000","+000+000-006","-000+000+006","-000+000-000"]},{"hall":142,"number":28,"symbol":"P -2a -2a","operations":["+000+000+000","+000+000-600","-000+000+600","-000+000-000"]},{"hall":143,"number":29,"symbol":"P 2c -2ac","operations":["+000+000+000","+000-000+600","-000+000+606","-000-000+006"]},{"hall":144,"number":29,"symbol":"P 2c -2b","operations":["+000+000+000","+000-000+066","-000+000+060","-000-000+006"]},{"hall":145,"number":29,"symbol":"P -2b 2a","operations":["+000+000+000","+000+000-060","+000-000+660","+000-000-600"]},{"hall":146,"number":29,"symbol":"P -2ac 2a","operations":["+000+000+000","+000+000-606","+000-000+006","+000-000-600"]},{"hall":147,"number":29,"symbol":"P -2bc -2c","operations":["+000+000+000","+000+000-066","-000+000+006","-000+000-060"]},{"hall":148,"number":29,"symbol":"P -2a -2ab","operations":["+000+000+000","+000+000-600","-000+000+660","-000+000-060"]},{"hall":149,"number":30,"symbol":"P 2 -2bc","operations":["+000+000+000","+000-000+066","-000+000+066","-000-000+000"]},{"hall":150,"number":30,"symbol":"P 2 -2ac","operations":["+000+000+000","+000-000+606","-000+000+606","-000-000+000"]},{"hall":151,"number":30,"symbol":"P -2ac 2","operations":["+000+000+000","+000+000-606","+000-000+606","+000-000-000"]},{"hall":152,"number":30,"symbol":"P -2ab 2","operations":["+000+000+000","+000+000-660","+000-000+660","+000-000-000"]},{"hall":153,"number":30,"symbol":"P -2ab -2ab","operations":["+000+000+000","+000+000-660","-000+000+660","-000+000-000"]},{"hall":154,"number":30,"symbol":"P -2bc -2bc","operations":["+000+000+000","+000+000-066","-000+000+066","-000+000-000"]},{"hall":155,"number":31,"symbol":"P 2ac -2","operations":["+000+000+000","+000-000+606","-000+000+000","-000-000+606"]},{"hall":156,"number":31,"symbol":"P 2bc -2bc","operations":["+000+000+000","+000-000+000","-000+000+066","-000-000+066"]},{"hall":157,"number":31,"symbol":"P -2ab 2ab","operations":["+000+000+000","+000+000-660","+000-000+000","+000-000-660"]},{"hall":158,"number":31,"symbol":"P -2 2ac","operations":["+000+000+000","+000+000-000","+000-000+606","+000-000-606"]},{"hall":159,"number":31,"symbol":"P -2 -2bc","operations":["+000+000+000","+000+000-000","-000+000+066","-000+000-066"]},{"hall":160,"number":31,"symbol":"P -2ab -2","operations":["+000+000+000","+000+000-660","-000+000+000","-000+000-660"]},{"hall":161,"number":32,"symbol":"P 2 -2ab","operations":["+000+000+000","+000-000+660","-000+000+660","-000-000+000"]},{"hall":162,"number":32,"symbol":"P -2bc 2","operations":["+000+000+000","+000+000-066","+000-000+066","+000-000-000"]},{"hall":163,"number":32,"symbol":"P -2ac -2ac","operations":["+000+000+000","+000+000-606","-000+000+606","-000+000-000"]},{"hall":164,"number":33,"symbol":"P 2c -2n","operations":["+000+000+000","+000-000+660","-000+000+666","-000-000+006"]},{"hall":165,"number":33,"symbol":"P 2c -2ab","operations":["+000+000+000","+000-000+666","-000+000+660","-000-000+006"]},{"hall":166,"number":33,"symbol":"P -2bc 2a","operations":["+000+000+000","+000+000-066","+000-000+666","+000-000-600"]},{"hall":167,"number":33,"symbol":"P -2n 2a","operations":["+000+000+000","+000+000-666","+000-000+066","+000-000-600"]},{"hall":168,"number":33,"symbol":"P -2n -2ac","operations":["+000+000+000","+000+000-666","-000+000+606","-000+000-060"]},{"hall":169,"number":33,"symbol":"P -2ac -2n","operations":["+000+000+000","+000+000-606","-000+000+666","-000+000-060"]},{"hall":170,"number":34,"symbol":"P 2 -2n","operations":["+000+000+000","+000-000+666","-000+000+666","-000-000+000"]},{"hall":171,"number":34,"symbol":"P -2n 2","operations":["+000+000+000","+000+000-666","+000-000+666","+000-000-000"]},{"hall":172,"number":34,"symbol":"P -2n -2n","operations":["+000+000+000","+000+000-666","-000+000+666","-000+000-000"]},{"hall":173,"number":35,"symbol":"C 2 -2","operations":["+000+000+000","+000+000+660","+000-000+000","+000-000+660","-000+000+000","-000+000+660","-000-000+000","-000-000+660"]},{"hall":174,"number":35,"symbol":"A -2 2","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066","+000-000+000","+000-000+066","+000-000-000","+000-000-066"]},{"hall":175,"number":35,"symbol":"B -2 -2","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606","-000+000+000","-000+000+606","-000+000-000","-000+000-606"]},{"hall":176,"number":36,"symbol":"C 2c -2","operations":["+000+000+000","+000+000+660","+000-000+006","+000-000+666","-000+000+000","-000+000+660","-000-000+006","-000-000+666"]},{"hall":177,"number":36,"symbol":"C 2c -2c","operations":["+000+000+000","+000+000+660","+000-000+000","+000-000+660","-000+000+006","-000+000+666","-000-000+006","-000-000+666"]},{"hall":178,"number":36,"symbol":"A -2a 2a","operations":["+000+000+000","+000+000+066","+000+000-600","+000+000-666","+000-000+000","+000-000+066","+000-000-600","+000-000-666"]},{"hall":179,"number":36,"symbol":"A -2 2a","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066","+000-000+600","+000-000+666","+000-000-600","+000-000-666"]},{"hall":180,"number":36,"symbol":"B -2 -2b","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606","-000+000+060","-000+000+666","-000+000-060","-000+000-666"]},{"hall":181,"number":36,"symbol":"B -2b -2","operations":["+000+000+000","+000+000+606","+000+000-060","+000+000-666","-000+000+000","-000+000+606","-000+000-060","-000+000-666"]},{"hall":182,"number":37,"symbol":"C 2 -2c","operations":["+000+000+000","+000+000+660","+000-000+006","+000-000+666","-000+000+006","-000+000+666","-000-000+000","-000-000+660"]},{"hall":183,"number":37,"symbol":"A -2a 2","operations":["+000+000+000","+000+000+066","+000+000-600","+000+000-666","+000-000+600","+000-000+666","+000-000-000","+000-000-066"]},{"hall":184,"number":37,"symbol":"B -2b -2b","operations":["+000+000+000","+000+000+606","+000+000-060","+000+000-666","-000+000+060","-000+000+666","-000+000-000","-000+000-606"]},{"hall":185,"number":38,"symbol":"A 2 -2","operations":["+000+000+000","+000+000+066","+000-000+000","+000-000+066","-000+000+000","-000+000+066","-000-000+000","-000-000+066"]},{"hall":186,"number":38,"symbol":"B 2 -2","operations":["+000+000+000","+000+000+606","+000-000+000","+000-000+606","-000+000+000","-000+000+606","-000-000+000","-000-000+606"]},{"hall":187,"number":38,"symbol":"B -2 2","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606","+000-000+000","+000-000+606","+000-000-000","+000-000-606"]},{"hall":188,"number":38,"symbol":"C -2 2","operations":["+000+000+000","+000+000+660","+000+000-000","+000+000-660","+000-000+000","+000-000+660","+000-000-000","+000-000-660"]},{"hall":189,"number":38,"symbol":"C -2 -2","operations":["+000+000+000","+000+000+660","+000+000-000","+000+000-660","-000+000+000","-000+000+660","-000+000-000","-000+000-660"]},{"hall":190,"number":38,"symbol":"A -2 -2","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066","-000+000+000","-000+000+066","-000+000-000","-000+000-066"]},{"hall":191,"number":39,"symbol":"A 2 -2b","operations":["+000+000+000","+000+000+066","+000-000+006","+000-000+060","-000+000+006","-000+000+060","-000-000+000","-000-000+066"]},{"hall":192,"number":39,"symbol":"B 2 -2a","operations":["+000+000+000","+000+000+606","+000-000+006","+000-000+600","-000+000+006","-000+000+600","-000-000+000","-000-000+606"]},{"hall":193,"number":39,"symbol":"B -2a 2","operations":["+000+000+000","+000+000+606","+000+000-006","+000+000-600","+000-000+006","+000-000+600","+000-000-000","+000-000-606"]},{"hall":194,"number":39,"symbol":"C -2a 2","operations":["+000+000+000","+000+000+660","+000+000-060","+000+000-600","+000-000+060","+000-000+600","+000-000-000","+000-000-660"]},{"hall":195,"number":39,"symbol":"C -2a -2a","operations":["+000+000+000","+000+000+660","+000+000-060","+000+000-600","-000+000+060","-000+000+600","-000+000-000","-000+000-660"]},{"hall":196,"number":39,"symbol":"A -2b -2b","operations":["+000+000+000","+000+000+066","+000+000-006","+000+000-060","-000+000+006","-000+000+060","-000+000-000","-000+000-066"]},{"hall":197,"number":40,"symbol":"A 2 -2a","operations":["+000+000+000","+000+000+066","+000-000+600","+000-000+666","-000+000+600","-000+000+666","-000-000+000","-000-000+066"]},{"hall":198,"number":40,"symbol":"B 2 -2b","operations":["+000+000+000","+000+000+606","+000-000+060","+000-000+666","-000+000+060","-000+000+666","-000-000+000","-000-000+606"]},{"hall":199,"number":40,"symbol":"B -2b 2","operations":["+000+000+000","+000+000+606","+000+000-060","+000+000-666","+000-000+060","+000-000+666","+000-000-000","+000-000-606"]},{"hall":200,"number":40,"symbol":"C -2c 2","operations":["+000+000+000","+000+000+660","+000+000-006","+000+000-666","+000-000+006","+000-000+666","+000-000-000","+000-000-660"]},{"hall":201,"number":40,"symbol":"C -2c -2c","operations":["+000+000+000","+000+000+660","+000+000-006","+000+000-666","-000+000+006","-000+000+666","-000+000-000","-000+000-660"]},{"hall":202,"number":40,"symbol":"A -2a -2a","operations":["+000+000+000","+000+000+066","+000+000-600","+000+000-666","-000+000+600","-000+000+666","-000+000-000","-000+000-066"]},{"hall":203,"number":41,"symbol":"A 2 -2ab","operations":["+000+000+000","+000+000+066","+000-000+606","+000-000+660","-000+000+606","-000+000+660","-000-000+000","-000-000+066"]},{"hall":204,"number":41,"symbol":"B 2 -2ab","operations":["+000+000+000","+000+000+606","+000-000+066","+000-000+660","-000+000+066","-000+000+660","-000-000+000","-000-000+606"]},{"hall":205,"number":41,"symbol":"B -2ab 2","operations":["+000+000+000","+000+000+606","+000+000-066","+000+000-660","+000-000+066","+000-000+660","+000-000-000","+000-000-606"]},{"hall":206,"number":41,"symbol":"C -2ac 2","operations":["+000+000+000","+000+000+660","+000+000-066","+000+000-606","+000-000+066","+000-000+606","+000-000-000","+000-000-660"]},{"hall":207,"number":41,"symbol":"C -2ac -2ac","operations":["+000+000+000","+000+000+660","+000+000-066","+000+000-606","-000+000+066","-000+000+606","-000+000-000","-000+000-660"]},{"hall":208,"number":41,"symbol":"A -2ab -2ab","operations":["+000+000+000","+000+000+066","+000+000-606","+000+000-660","-000+000+606","-000+000+660","-000+000-000","-000+000-066"]},{"hall":209,"number":42,"symbol":"F 2 -2","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000-000+000","+000-000+066","+000-000+606","+000-000+660","-000+000+000","-000+000+066","-000+000+606","-000+000+660","-000-000+000","-000-000+066","-000-000+606","-000-000+660"]},{"hall":210,"number":42,"symbol":"F -2 2","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-000","+000+000-066","+000+000-606","+000+000-660","+000-000+000","+000-000+066","+000-000+606","+000-000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660"]},{"hall":211,"number":42,"symbol":"F -2 -2","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-000","+000+000-066","+000+000-606","+000+000-660","-000+000+000","-000+000+066","-000+000+606","-000+000+660","-000+000-000","-000+000-066","-000+000-606","-000+000-660"]},{"hall":212,"number":43,"symbol":"F 2 -2d","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000-000+333","+000-000+399","+000-000+939","+000-000+993","-000+000+333","-000+000+399","-000+000+939","-000+000+993","-000-000+000","-000-000+066","-000-000+606","-000-000+660"]},{"hall":213,"number":43,"symbol":"F -2d 2","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-333","+000+000-399","+000+000-939","+000+000-993","+000-000+333","+000-000+399","+000-000+939","+000-000+993","+000-000-000","+000-000-066","+000-000-606","+000-000-660"]},{"hall":214,"number":43,"symbol":"F -2d -2d","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-333","+000+000-399","+000+000-939","+000+000-993","-000+000+333","-000+000+399","-000+000+939","-000+000+993","-000+000-000","-000+000-066","-000+000-606","-000+000-660"]},{"hall":215,"number":44,"symbol":"I 2 -2","operations":["+000+000+000","+000+000+666","+000-000+000","+000-000+666","-000+000+000","-000+000+666","-000-000+000","-000-000+666"]},{"hall":216,"number":44,"symbol":"I -2 2","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+000","+000-000+666","+000-000-000","+000-000-666"]},{"hall":217,"number":44,"symbol":"I -2 -2","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","-000+000+000","-000+000+666","-000+000-000","-000+000-666"]},{"hall":218,"number":45,"symbol":"I 2 -2c","operations":["+000+000+000","+000+000+666","+000-000+006","+000-000+660","-000+000+006","-000+000+660","-000-000+000","-000-000+666"]},{"hall":219,"number":45,"symbol":"I -2a 2","operations":["+000+000+000","+000+000+666","+000+000-066","+000+000-600","+000-000+066","+000-000+600","+000-000-000","+000-000-666"]},{"hall":220,"number":45,"symbol":"I -2b -2b","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","-000+000+060","-000+000+606","-000+000-000","-000+000-666"]},{"hall":221,"number":46,"symbol":"I 2 -2a","operations":["+000+000+000","+000+000+666","+000-000+066","+000-000+600","-000+000+066","-000+000+600","-000-000+000","-000-000+666"]},{"hall":222,"number":46,"symbol":"I 2 -2b","operations":["+000+000+000","+000+000+666","+000-000+060","+000-000+606","-000+000+060","-000+000+606","-000-000+000","-000-000+666"]},{"hall":223,"number":46,"symbol":"I -2b 2","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","+000-000+060","+000-000+606","+000-000-000","+000-000-666"]},{"hall":224,"number":46,"symbol":"I -2c 2","operations":["+000+000+000","+000+000+666","+000+000-006","+000+000-660","+000-000+006","+000-000+660","+000-000-000","+000-000-666"]},{"hall":225,"number":46,"symbol":"I -2c -2c","operations":["+000+000+000","+000+000+666","+000+000-006","+000+000-660","-000+000+006","-000+000+660","-000+000-000","-000+000-666"]},{"hall":226,"number":46,"symbol":"I -2a -2a","operations":["+000+000+000","+000+000+666","+000+000-066","+000+000-600","-000+000+066","-000+000+600","-000+000-000","-000+000-666"]},{"hall":227,"number":47,"symbol":"-P 2 2","operations":["+000+000+000","+000+000-000","+000-000+000","+000-000-000","-000+000+000","-000+000-000","-000-000+000","-000-000-000"]},{"hall":228,"number":48,"symbol":"P 2 2 -1n","operations":["+000+000+000","+000+000-666","+000-000+666","+000-000-000","-000+000+666","-000+000-000","-000-000+000","-000-000-666"]},{"hall":229,"number":48,"symbol":"-P 2ab 2bc","operations":["+000+000+000","+000+000-660","+000-000+606","+000-000-066","-000+000+066","-000+000-606","-000-000+660","-000-000-000"]},{"hall":230,"number":49,"symbol":"-P 2 2c","operations":["+000+000+000","+000+000-000","+000-000+006","+000-000-006","-000+000+006","-000+000-006","-000-000+000","-000-000-000"]},{"hall":231,"number":49,"symbol":"-P 2a 2","operations":["+000+000+000","+000+000-600","+000-000+600","+000-000-000","-000+000+000","-000+000-600","-000-000+600","-000-000-000"]},{"hall":232,"number":49,"symbol":"-P 2b 2b","operations":["+000+000+000","+000+000-060","+000-000+000","+000-000-060","-000+000+060","-000+000-000","-000-000+060","-000-000-000"]},{"hall":233,"number":50,"symbol":"P 2 2 -1ab","operations":["+000+000+000","+000+000-660","+000-000+660","+000-000-000","-000+000+660","-000+000-000","-000-000+000","-000-000-660"]},{"hall":234,"number":50,"symbol":"-P 2ab 2b","operations":["+000+000+000","+000+000-660","+000-000+600","+000-000-060","-000+000+060","-000+000-600","-000-000+660","-000-000-000"]},{"hall":235,"number":50,"symbol":"P 2 2 -1bc","operations":["+000+000+000","+000+000-066","+000-000+066","+000-000-000","-000+000+066","-000+000-000","-000-000+000","-000-000-066"]},{"hall":236,"number":50,"symbol":"-P 2b 2bc","operations":["+000+000+000","+000+000-060","+000-000+006","+000-000-066","-000+000+066","-000+000-006","-000-000+060","-000-000-000"]},{"hall":237,"number":50,"symbol":"P 2 2 -1ac","operations":["+000+000+000","+000+000-606","+000-000+606","+000-000-000","-000+000+606","-000+000-000","-000-000+000","-000-000-606"]},{"hall":238,"number":50,"symbol":"-P 2a 2c","operations":["+000+000+000","+000+000-600","+000-000+606","+000-000-006","-000+000+006","-000+000-606","-000-000+600","-000-000-000"]},{"hall":239,"number":51,"symbol":"-P 2a 2a","operations":["+000+000+000","+000+000-600","+000-000+000","+000-000-600","-000+000+600","-000+000-000","-000-000+600","-000-000-000"]},{"hall":240,"number":51,"symbol":"-P 2b 2","operations":["+000+000+000","+000+000-060","+000-000+060","+000-000-000","-000+000+000","-000+000-060","-000-000+060","-000-000-000"]},{"hall":241,"number":51,"symbol":"-P 2 2b","operations":["+000+000+000","+000+000-000","+000-000+060","+000-000-060","-000+000+060","-000+000-060","-000-000+000","-000-000-000"]},{"hall":242,"number":51,"symbol":"-P 2c 2c","operations":["+000+000+000","+000+000-006","+000-000+000","+000-000-006","-000+000+006","-000+000-000","-000-000+006","-000-000-000"]},{"hall":243,"number":51,"symbol":"-P 2c 2","operations":["+000+000+000","+000+000-006","+000-000+006","+000-000-000","-000+000+000","-000+000-006","-000-000+006","-000-000-000"]},{"hall":244,"number":51,"symbol":"-P 2 2a","operations":["+000+000+000","+000+000-000","+000-000+600","+000-000-600","-000+000+600","-000+000-600","-000-000+000","-000-000-000"]},{"hall":245,"number":52,"symbol":"-P 2a 2bc","operations":["+000+000+000","+000+000-600","+000-000+666","+000-000-066","-000+000+066","-000+000-666","-000-000+600","-000-000-000"]},{"hall":246,"number":52,"symbol":"-P 2b 2n","operations":["+000+000+000","+000+000-060","+000-000+606","+000-000-666","-000+000+666","-000+000-606","-000-000+060","-000-000-000"]},{"hall":247,"number":52,"symbol":"-P 2n 2b","operations":["+000+000+000","+000+000-666","+000-000+606","+000-000-060","-000+000+060","-000+000-606","-000-000+666","-000-000-000"]},{"hall":248,"number":52,"symbol":"-P 2ab 2c","operations":["+000+000+000","+000+000-660","+000-000+666","+000-000-006","-000+000+006","-000+000-666","-000-000+660","-000-000-000"]},{"hall":249,"number":52,"symbol":"-P 2ab 2n","operations":["+000+000+000","+000+000-660","+000-000+006","+000-000-666","-000+000+666","-000+000-006","-000-000+660","-000-000-000"]},{"hall":250,"number":52,"symbol":"-P 2n 2bc","operations":["+000+000+000","+000+000-666","+000-000+600","+000-000-066","-000+000+066","-000+000-600","-000-000+666","-000-000-000"]},{"hall":251,"number":53,"symbol":"-P 2ac 2","operations":["+000+000+000","+000+000-606","+000-000+606","+000-000-000","-000+000+000","-000+000-606","-000-000+606","-000-000-000"]},{"hall":252,"number":53,"symbol":"-P 2bc 2bc","operations":["+000+000+000","+000+000-066","+000-000+000","+000-000-066","-000+000+066","-000+000-000","-000-000+066","-000-000-000"]},{"hall":253,"number":53,"symbol":"-P 2ab 2ab","operations":["+000+000+000","+000+000-660","+000-000+000","+000-000-660","-000+000+660","-000+000-000","-000-000+660","-000-000-000"]},{"hall":254,"number":53,"symbol":"-P 2 2ac","operations":["+000+000+000","+000+000-000","+000-000+606","+000-000-606","-000+000+606","-000+000-606","-000-000+000","-000-000-000"]},{"hall":255,"number":53,"symbol":"-P 2 2bc","operations":["+000+000+000","+000+000-000","+000-000+066","+000-000-066","-000+000+066","-000+000-066","-000-000+000","-000-000-000"]},{"hall":256,"number":53,"symbol":"-P 2ab 2","operations":["+000+000+000","+000+000-660","+000-000+660","+000-000-000","-000+000+000","-000+000-660","-000-000+660","-000-000-000"]},{"hall":257,"number":54,"symbol":"-P 2a 2ac","operations":["+000+000+000","+000+000-600","+000-000+006","+000-000-606","-000+000+606","-000+000-006","-000-000+600","-000-000-000"]},{"hall":258,"number":54,"symbol":"-P 2b 2c","operations":["+000+000+000","+000+000-060","+000-000+066","+000-000-006","-000+000+006","-000+000-066","-000-000+060","-000-000-000"]},{"hall":259,"number":54,"symbol":"-P 2a 2b","operations":["+000+000+000","+000+000-600","+000-000+660","+000-000-060","-000+000+060","-000+000-660","-000-000+600","-000-000-000"]},{"hall":260,"number":54,"symbol":"-P 2ac 2c","operations":["+000+000+000","+000+000-606","+000-000+600","+000-000-006","-000+000+006","-000+000-600","-000-000+606","-000-000-000"]},{"hall":261,"number":54,"symbol":"-P 2bc 2b","operations":["+000+000+000","+000+000-066","+000-000+006","+000-000-060","-000+000+060","-000+000-006","-000-000+066","-000-000-000"]},{"hall":262,"number":54,"symbol":"-P 2b 2ab","operations":["+000+000+000","+000+000-060","+000-000+600","+000-000-660","-000+000+660","-000+000-600","-000-000+060","-000-000-000"]},{"hall":263,"number":55,"symbol":"-P 2 2ab","operations":["+000+000+000","+000+000-000","+000-000+660","+000-000-660","-000+000+660","-000+000-660","-000-000+000","-000-000-000"]},{"hall":264,"number":55,"symbol":"-P 2bc 2","operations":["+000+000+000","+000+000-066","+000-000+066","+000-000-000","-000+000+000","-000+000-066","-000-000+066","-000-000-000"]},{"hall":265,"number":55,"symbol":"-P 2ac 2ac","operations":["+000+000+000","+000+000-606","+000-000+000","+000-000-606","-000+000+606","-000+000-000","-000-000+606","-000-000-000"]},{"hall":266,"number":56,"symbol":"-P 2ab 2ac","operations":["+000+000+000","+000+000-660","+000-000+066","+000-000-606","-000+000+606","-000+000-066","-000-000+660","-000-000-000"]},{"hall":267,"number":56,"symbol":"-P 2ac 2bc","operations":["+000+000+000","+000+000-606","+000-000+660","+000-000-066","-000+000+066","-000+000-660","-000-000+606","-000-000-000"]},{"hall":268,"number":56,"symbol":"-P 2bc 2ab","operations":["+000+000+000","+000+000-066","+000-000+606","+000-000-660","-000+000+660","-000+000-606","-000-000+066","-000-000-000"]},{"hall":269,"number":57,"symbol":"-P 2c 2b","operations":["+000+000+000","+000+000-006","+000-000+066","+000-000-060","-000+000+060","-000+000-066","-000-000+006","-000-000-000"]},{"hall":270,"number":57,"symbol":"-P 2c 2ac","operations":["+000+000+000","+000+000-006","+000-000+600","+000-000-606","-000+000+606","-000+000-600","-000-000+006","-000-000-000"]},{"hall":271,"number":57,"symbol":"-P 2ac 2a","operations":["+000+000+000","+000+000-606","+000-000+006","+000-000-600","-000+000+600","-000+000-006","-000-000+606","-000-000-000"]},{"hall":272,"number":57,"symbol":"-P 2b 2a","operations":["+000+000+000","+000+000-060","+000-000+660","+000-000-600","-000+000+600","-000+000-660","-000-000+060","-000-000-000"]},{"hall":273,"number":57,"symbol":"-P 2a 2ab","operations":["+000+000+000","+000+000-600","+000-000+060","+000-000-660","-000+000+660","-000+000-060","-000-000+600","-000-000-000"]},{"hall":274,"number":57,"symbol":"-P 2bc 2c","operations":["+000+000+000","+000+000-066","+000-000+060","+000-000-006","-000+000+006","-000+000-060","-000-000+066","-000-000-000"]},{"hall":275,"number":58,"symbol":"-P 2 2n","operations":["+000+000+000","+000+000-000","+000-000+666","+000-000-666","-000+000+666","-000+000-666","-000-000+000","-000-000-000"]},{"hall":276,"number":58,"symbol":"-P 2n 2","operations":["+000+000+000","+000+000-666","+000-000+666","+000-000-000","-000+000+000","-000+000-666","-000-000+666","-000-000-000"]},{"hall":277,"number":58,"symbol":"-P 2n 2n","operations":["+000+000+000","+000+000-666","+000-000+000","+000-000-666","-000+000+666","-000+000-000","-000-000+666","-000-000-000"]},{"hall":278,"number":59,"symbol":"P 2 2ab -1ab","operations":["+000+000+000","+000+000-660","+000-000+000","+000-000-660","-000+000+000","-000+000-660","-000-000+000","-000-000-660"]},{"hall":279,"number":59,"symbol":"-P 2ab 2a","operations":["+000+000+000","+000+000-660","+000-000+060","+000-000-600","-000+000+600","-000+000-060","-000-000+660","-000-000-000"]},{"hall":280,"number":59,"symbol":"P 2bc 2 -1bc","operations":["+000+000+000","+000+000-000","+000-000+000","+000-000-000","-000+000+066","-000+000-066","-000-000+066","-000-000-066"]},{"hall":281,"number":59,"symbol":"-P 2c 2bc","operations":["+000+000+000","+000+000-006","+000-000+060","+000-000-066","-000+000+066","-000+000-060","-000-000+006","-000-000-000"]},{"hall":282,"number":59,"symbol":"P 2ac 2ac -1ac","operations":["+000+000+000","+000+000-000","+000-000+606","+000-000-606","-000+000+000","-000+000-000","-000-000+606","-000-000-606"]},{"hall":283,"number":59,"symbol":"-P 2c 2a","operations":["+000+000+000","+000+000-006","+000-000+606","+000-000-600","-000+000+600","-000+000-606","-000-000+006","-000-000-000"]},{"hall":284,"number":60,"symbol":"-P 2n 2ab","operations":["+000+000+000","+000+000-666","+000-000+006","+000-000-660","-000+000+660","-000+000-006","-000-000+666","-000-000-000"]},{"hall":285,"number":60,"symbol":"-P 2n 2c","operations":["+000+000+000","+000+000-666","+000-000+660","+000-000-006","-000+000+006","-000+000-660","-000-000+666","-000-000-000"]},{"hall":286,"number":60,"symbol":"-P 2a 2n","operations":["+000+000+000","+000+000-600","+000-000+066","+000-000-666","-000+000+666","-000+000-066","-000-000+600","-000-000-000"]},{"hall":287,"number":60,"symbol":"-P 2bc 2n","operations":["+000+000+000","+000+000-066","+000-000+600","+000-000-666","-000+000+666","-000+000-600","-000-000+066","-000-000-000"]},{"hall":288,"number":60,"symbol":"-P 2ac 2b","operations":["+000+000+000","+000+000-606","+000-000+666","+000-000-060","-000+000+060","-000+000-666","-000-000+606","-000-000-000"]},{"hall":289,"number":60,"symbol":"-P 2b 2ac","operations":["+000+000+000","+000+000-060","+000-000+666","+000-000-606","-000+000+606","-000+000-666","-000-000+060","-000-000-000"]},{"hall":290,"number":61,"symbol":"-P 2ac 2ab","operations":["+000+000+000","+000+000-606","+000-000+066","+000-000-660","-000+000+660","-000+000-066","-000-000+606","-000-000-000"]},{"hall":291,"number":61,"symbol":"-P 2bc 2ac","operations":["+000+000+000","+000+000-066","+000-000+660","+000-000-606","-000+000+606","-000+000-660","-000-000+066","-000-000-000"]},{"hall":292,"number":62,"symbol":"-P 2ac 2n","operations":["+000+000+000","+000+000-606","+000-000+060","+000-000-666","-000+000+666","-000+000-060","-000-000+606","-000-000-000"]},{"hall":293,"number":62,"symbol":"-P 2bc 2a","operations":["+000+000+000","+000+000-066","+000-000+666","+000-000-600","-000+000+600","-000+000-666","-000-000+066","-000-000-000"]},{"hall":294,"number":62,"symbol":"-P 2c 2ab","operations":["+000+000+000","+000+000-006","+000-000+666","+000-000-660","-000+000+660","-000+000-666","-000-000+006","-000-000-000"]},{"hall":295,"number":62,"symbol":"-P 2n 2ac","operations":["+000+000+000","+000+000-666","+000-000+060","+000-000-606","-000+000+606","-000+000-060","-000-000+666","-000-000-000"]},{"hall":296,"number":62,"symbol":"-P 2n 2a","operations":["+000+000+000","+000+000-666","+000-000+066","+000-000-600","-000+000+600","-000+000-066","-000-000+666","-000-000-000"]},{"hall":297,"number":62,"symbol":"-P 2c 2n","operations":["+000+000+000","+000+000-006","+000-000+660","+000-000-666","-000+000+666","-000+000-660","-000-000+006","-000-000-000"]},{"hall":298,"number":63,"symbol":"-C 2c 2","operations":["+000+000+000","+000+000+660","+000+000-006","+000+000-666","+000-000+006","+000-000+666","+000-000-000","+000-000-660","-000+000+000","-000+000+660","-000+000-006","-000+000-666","-000-000+006","-000-000+666","-000-000-000","-000-000-660"]},{"hall":299,"number":63,"symbol":"-C 2c 2c","operations":["+000+000+000","+000+000+660","+000+000-006","+000+000-666","+000-000+000","+000-000+660","+000-000-006","+000-000-666","-000+000+006","-000+000+666","-000+000-000","-000+000-660","-000-000+006","-000-000+666","-000-000-000","-000-000-660"]},{"hall":300,"number":63,"symbol":"-A 2a 2a","operations":["+000+000+000","+000+000+066","+000+000-600","+000+000-666","+000-000+000","+000-000+066","+000-000-600","+000-000-666","-000+000+600","-000+000+666","-000+000-000","-000+000-066","-000-000+600","-000-000+666","-000-000-000","-000-000-066"]},{"hall":301,"number":63,"symbol":"-A 2 2a","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066","+000-000+600","+000-000+666","+000-000-600","+000-000-666","-000+000+600","-000+000+666","-000+000-600","-000+000-666","-000-000+000","-000-000+066","-000-000-000","-000-000-066"]},{"hall":302,"number":63,"symbol":"-B 2 2b","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606","+000-000+060","+000-000+666","+000-000-060","+000-000-666","-000+000+060","-000+000+666","-000+000-060","-000+000-666","-000-000+000","-000-000+606","-000-000-000","-000-000-606"]},{"hall":303,"number":63,"symbol":"-B 2b 2","operations":["+000+000+000","+000+000+606","+000+000-060","+000+000-666","+000-000+060","+000-000+666","+000-000-000","+000-000-606","-000+000+000","-000+000+606","-000+000-060","-000+000-666","-000-000+060","-000-000+666","-000-000-000","-000-000-606"]},{"hall":304,"number":64,"symbol":"-C 2ac 2","operations":["+000+000+000","+000+000+660","+000+000-066","+000+000-606","+000-000+066","+000-000+606","+000-000-000","+000-000-660","-000+000+000","-000+000+660","-000+000-066","-000+000-606","-000-000+066","-000-000+606","-000-000-000","-000-000-660"]},{"hall":305,"number":64,"symbol":"-C 2ac 2ac","operations":["+000+000+000","+000+000+660","+000+000-066","+000+000-606","+000-000+000","+000-000+660","+000-000-066","+000-000-606","-000+000+066","-000+000+606","-000+000-000","-000+000-660","-000-000+066","-000-000+606","-000-000-000","-000-000-660"]},{"hall":306,"number":64,"symbol":"-A 2ab 2ab","operations":["+000+000+000","+000+000+066","+000+000-606","+000+000-660","+000-000+000","+000-000+066","+000-000-606","+000-000-660","-000+000+606","-000+000+660","-000+000-000","-000+000-066","-000-000+606","-000-000+660","-000-000-000","-000-000-066"]},{"hall":307,"number":64,"symbol":"-A 2 2ab","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066","+000-000+606","+000-000+660","+000-000-606","+000-000-660","-000+000+606","-000+000+660","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000-000","-000-000-066"]},{"hall":308,"number":64,"symbol":"-B 2 2ab","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606","+000-000+066","+000-000+660","+000-000-066","+000-000-660","-000+000+066","-000+000+660","-000+000-066","-000+000-660","-000-000+000","-000-000+606","-000-000-000","-000-000-606"]},{"hall":309,"number":64,"symbol":"-B 2ab 2","operations":["+000+000+000","+000+000+606","+000+000-066","+000+000-660","+000-000+066","+000-000+660","+000-000-000","+000-000-606","-000+000+000","-000+000+606","-000+000-066","-000+000-660","-000-000+066","-000-000+660","-000-000-000","-000-000-606"]},{"hall":310,"number":65,"symbol":"-C 2 2","operations":["+000+000+000","+000+000+660","+000+000-000","+000+000-660","+000-000+000","+000-000+660","+000-000-000","+000-000-660","-000+000+000","-000+000+660","-000+000-000","-000+000-660","-000-000+000","-000-000+660","-000-000-000","-000-000-660"]},{"hall":311,"number":65,"symbol":"-A 2 2","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066","+000-000+000","+000-000+066","+000-000-000","+000-000-066","-000+000+000","-000+000+066","-000+000-000","-000+000-066","-000-000+000","-000-000+066","-000-000-000","-000-000-066"]},{"hall":312,"number":65,"symbol":"-B 2 2","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606","+000-000+000","+000-000+606","+000-000-000","+000-000-606","-000+000+000","-000+000+606","-000+000-000","-000+000-606","-000-000+000","-000-000+606","-000-000-000","-000-000-606"]},{"hall":313,"number":66,"symbol":"-C 2 2c","operations":["+000+000+000","+000+000+660","+000+000-000","+000+000-660","+000-000+006","+000-000+666","+000-000-006","+000-000-666","-000+000+006","-000+000+666","-000+000-006","-000+000-666","-000-000+000","-000-000+660","-000-000-000","-000-000-660"]},{"hall":314,"number":66,"symbol":"-A 2a 2","operations":["+000+000+000","+000+000+066","+000+000-600","+000+000-666","+000-000+600","+000-000+666","+000-000-000","+000-000-066","-000+000+000","-000+000+066","-000+000-600","-000+000-666","-000-000+600","-000-000+666","-000-000-000","-000-000-066"]},{"hall":315,"number":66,"symbol":"-B 2b 2b","operations":["+000+000+000","+000+000+606","+000+000-060","+000+000-666","+000-000+000","+000-000+606","+000-000-060","+000-000-666","-000+000+060","-000+000+666","-000+000-000","-000+000-606","-000-000+060","-000-000+666","-000-000-000","-000-000-606"]},{"hall":316,"number":67,"symbol":"-C 2a 2","operations":["+000+000+000","+000+000+660","+000+000-060","+000+000-600","+000-000+060","+000-000+600","+000-000-000","+000-000-660","-000+000+000","-000+000+660","-000+000-060","-000+000-600","-000-000+060","-000-000+600","-000-000-000","-000-000-660"]},{"hall":317,"number":67,"symbol":"-C 2a 2a","operations":["+000+000+000","+000+000+660","+000+000-060","+000+000-600","+000-000+000","+000-000+660","+000-000-060","+000-000-600","-000+000+060","-000+000+600","-000+000-000","-000+000-660","-000-000+060","-000-000+600","-000-000-000","-000-000-660"]},{"hall":318,"number":67,"symbol":"-A 2b 2b","operations":["+000+000+000","+000+000+066","+000+000-006","+000+000-060","+000-000+000","+000-000+066","+000-000-006","+000-000-060","-000+000+006","-000+000+060","-000+000-000","-000+000-066","-000-000+006","-000-000+060","-000-000-000","-000-000-066"]},{"hall":319,"number":67,"symbol":"-A 2 2b","operations":["+000+000+000","+000+000+066","+000+000-000","+000+000-066","+000-000+006","+000-000+060","+000-000-006","+000-000-060","-000+000+006","-000+000+060","-000+000-006","-000+000-060","-000-000+000","-000-000+066","-000-000-000","-000-000-066"]},{"hall":320,"number":67,"symbol":"-B 2 2a","operations":["+000+000+000","+000+000+606","+000+000-000","+000+000-606","+000-000+006","+000-000+600","+000-000-006","+000-000-600","-000+000+006","-000+000+600","-000+000-006","-000+000-600","-000-000+000","-000-000+606","-000-000-000","-000-000-606"]},{"hall":321,"number":67,"symbol":"-B 2a 2","operations":["+000+000+000","+000+000+606","+000+000-006","+000+000-600","+000-000+006","+000-000+600","+000-000-000","+000-000-606","-000+000+000","-000+000+606","-000+000-006","-000+000-600","-000-000+006","-000-000+600","-000-000-000","-000-000-606"]},{"hall":322,"number":68,"symbol":"C 2 2 -1ac","operations":["+000+000+000","+000+000+660","+000+000-066","+000+000-606","+000-000+066","+000-000+606","+000-000-000","+000-000-660","-000+000+066","-000+000+606","-000+000-000","-000+000-660","-000-000+000","-000-000+660","-000-000-066","-000-000-606"]},{"hall":323,"number":68,"symbol":"-C 2a 2ac","operations":["+000+000+000","+000+000+660","+000+000-060","+000+000-600","+000-000+006","+000-000+666","+000-000-066","+000-000-606","-000+000+066","-000+000+606","-000+000-006","-000+000-666","-000-000+060","-000-000+600","-000-000-000","-000-000-660"]},{"hall":324,"number":68,"symbol":"C 2 2 -1ac","operations":["+000+000+000","+000+000+660","+000+000-066","+000+000-606","+000-000+066","+000-000+606","+000-000-000","+000-000-660","-000+000+066","-000+000+606","-000+000-000","-000+000-660","-000-000+000","-000-000+660","-000-000-066","-000-000-606"]},{"hall":325,"number":68,"symbol":"-C 2a 2c","operations":["+000+000+000","+000+000+660","+000+000-060","+000+000-600","+000-000+066","+000-000+606","+000-000-006","+000-000-666","-000+000+006","-000+000+666","-000+000-066","-000+000-606","-000-000+060","-000-000+600","-000-000-000","-000-000-660"]},{"hall":326,"number":68,"symbol":"A 2 2 -1ab","operations":["+000+000+000","+000+000+066","+000+000-606","+000+000-660","+000-000+606","+000-000+660","+000-000-000","+000-000-066","-000+000+606","-000+000+660","-000+000-000","-000+000-066","-000-000+000","-000-000+066","-000-000-606","-000-000-660"]},{"hall":327,"number":68,"symbol":"-A 2a 2b","operations":["+000+000+000","+000+000+066","+000+000-600","+000+000-666","+000-000+606","+000-000+660","+000-000-006","+000-000-060","-000+000+006","-000+000+060","-000+000-606","-000+000-660","-000-000+600","-000-000+666","-000-000-000","-000-000-066"]},{"hall":328,"number":68,"symbol":"A 2 2 -1ab","operations":["+000+000+000","+000+000+066","+000+000-606","+000+000-660","+000-000+606","+000-000+660","+000-000-000","+000-000-066","-000+000+606","-000+000+660","-000+000-000","-000+000-066","-000-000+000","-000-000+066","-000-000-606","-000-000-660"]},{"hall":329,"number":68,"symbol":"-A 2ab 2b","operations":["+000+000+000","+000+000+066","+000+000-606","+000+000-660","+000-000+600","+000-000+666","+000-000-006","+000-000-060","-000+000+006","-000+000+060","-000+000-600","-000+000-666","-000-000+606","-000-000+660","-000-000-000","-000-000-066"]},{"hall":330,"number":68,"symbol":"B 2 2 -1ab","operations":["+000+000+000","+000+000+606","+000+000-066","+000+000-660","+000-000+066","+000-000+660","+000-000-000","+000-000-606","-000+000+066","-000+000+660","-000+000-000","-000+000-606","-000-000+000","-000-000+606","-000-000-066","-000-000-660"]},{"hall":331,"number":68,"symbol":"-B 2ab 2b","operations":["+000+000+000","+000+000+606","+000+000-066","+000+000-660","+000-000+006","+000-000+600","+000-000-060","+000-000-666","-000+000+060","-000+000+666","-000+000-006","-000+000-600","-000-000+066","-000-000+660","-000-000-000","-000-000-606"]},{"hall":332,"number":68,"symbol":"B 2 2 -1ab","operations":["+000+000+000","+000+000+606","+000+000-066","+000+000-660","+000-000+066","+000-000+660","+000-000-000","+000-000-606","-000+000+066","-000+000+660","-000+000-000","-000+000-606","-000-000+000","-000-000+606","-000-000-066","-000-000-660"]},{"hall":333,"number":68,"symbol":"-B 2b 2ab","operations":["+000+000+000","+000+000+606","+000+000-060","+000+000-666","+000-000+006","+000-000+600","+000-000-066","+000-000-660","-000+000+066","-000+000+660","-000+000-006","-000+000-600","-000-000+060","-000-000+666","-000-000-000","-000-000-606"]},{"hall":334,"number":69,"symbol":"-F 2 2","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-000","+000+000-066","+000+000-606","+000+000-660","+000-000+000","+000-000+066","+000-000+606","+000-000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","-000+000+000","-000+000+066","-000+000+606","-000+000+660","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-000-000-000","-000-000-066","-000-000-606","-000-000-660"]},{"hall":335,"number":70,"symbol":"F 2 2 -1d","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-333","+000+000-399","+000+000-939","+000+000-993","+000-000+333","+000-000+399","+000-000+939","+000-000+993","+000-000-000","+000-000-066","+000-000-606","+000-000-660","-000+000+333","-000+000+399","-000+000+939","-000+000+993","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-000-000-333","-000-000-399","-000-000-939","-000-000-993"]},{"hall":336,"number":70,"symbol":"-F 2uv 2vw","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-330","+000+000-396","+000+000-936","+000+000-990","+000-000+303","+000-000+369","+000-000+909","+000-000+963","+000-000-033","+000-000-099","+000-000-639","+000-000-693","-000+000+033","-000+000+099","-000+000+639","-000+000+693","-000+000-303","-000+000-369","-000+000-909","-000+000-963","-000-000+330","-000-000+396","-000-000+936","-000-000+990","-000-000-000","-000-000-066","-000-000-606","-000-000-660"]},{"hall":337,"number":71,"symbol":"-I 2 2","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+000","+000-000+666","+000-000-000","+000-000-666","-000+000+000","-000+000+666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","-000-000-000","-000-000-666"]},{"hall":338,"number":72,"symbol":"-I 2 2c","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+006","+000-000+660","+000-000-006","+000-000-660","-000+000+006","-000+000+660","-000+000-006","-000+000-660","-000-000+000","-000-000+666","-000-000-000","-000-000-666"]},{"hall":339,"number":72,"symbol":"-I 2a 2","operations":["+000+000+000","+000+000+666","+000+000-066","+000+000-600","+000-000+066","+000-000+600","+000-000-000","+000-000-666","-000+000+000","-000+000+666","-000+000-066","-000+000-600","-000-000+066","-000-000+600","-000-000-000","-000-000-666"]},{"hall":340,"number":72,"symbol":"-I 2b 2b","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","+000-000+000","+000-000+666","+000-000-060","+000-000-606","-000+000+060","-000+000+606","-000+000-000","-000+000-666","-000-000+060","-000-000+606","-000-000-000","-000-000-666"]},{"hall":341,"number":73,"symbol":"-I 2b 2c","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","+000-000+066","+000-000+600","+000-000-006","+000-000-660","-000+000+006","-000+000+660","-000+000-066","-000+000-600","-000-000+060","-000-000+606","-000-000-000","-000-000-666"]},{"hall":342,"number":73,"symbol":"-I 2a 2b","operations":["+000+000+000","+000+000+666","+000+000-066","+000+000-600","+000-000+006","+000-000+660","+000-000-060","+000-000-606","-000+000+060","-000+000+606","-000+000-006","-000+000-660","-000-000+066","-000-000+600","-000-000-000","-000-000-666"]},{"hall":343,"number":74,"symbol":"-I 2b 2","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","+000-000+060","+000-000+606","+000-000-000","+000-000-666","-000+000+000","-000+000+666","-000+000-060","-000+000-606","-000-000+060","-000-000+606","-000-000-000","-000-000-666"]},{"hall":344,"number":74,"symbol":"-I 2a 2a","operations":["+000+000+000","+000+000+666","+000+000-066","+000+000-600","+000-000+000","+000-000+666","+000-000-066","+000-000-600","-000+000+066","-000+000+600","-000+000-000","-000+000-666","-000-000+066","-000-000+600","-000-000-000","-000-000-666"]},{"hall":345,"number":74,"symbol":"-I 2c 2c","operations":["+000+000+000","+000+000+666","+000+000-006","+000+000-660","+000-000+000","+000-000+666","+000-000-006","+000-000-660","-000+000+006","-000+000+660","-000+000-000","-000+000-666","-000-000+006","-000-000+660","-000-000-000","-000-000-666"]},{"hall":346,"number":74,"symbol":"-I 2 2b","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+060","+000-000+606","+000-000-060","+000-000-606","-000+000+060","-000+000+606","-000+000-060","-000+000-606","-000-000+000","-000-000+666","-000-000-000","-000-000-666"]},{"hall":347,"number":74,"symbol":"-I 2 2a","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+066","+000-000+600","+000-000-066","+000-000-600","-000+000+066","-000+000+600","-000+000-066","-000+000-600","-000-000+000","-000-000+666","-000-000-000","-000-000-666"]},{"hall":348,"number":74,"symbol":"-I 2c 2","operations":["+000+000+000","+000+000+666","+000+000-006","+000+000-660","+000-000+006","+000-000+660","+000-000-000","+000-000-666","-000+000+000","-000+000+666","-000+000-006","-000+000-660","-000-000+006","-000-000+660","-000-000-000","-000-000-666"]},{"hall":349,"number":75,"symbol":"P 4","operations":["+000+000+000","-000-000+000","0+0-0000+000","0-0+0000+000"]},{"hall":350,"number":76,"symbol":"P 4w","operations":["+000+000+000","-000-000+006","0+0-0000+009","0-0+0000+003"]},{"hall":351,"number":77,"symbol":"P 4c","operations":["+000+000+000","-000-000+000","0+0-0000+006","0-0+0000+006"]},{"hall":352,"number":78,"symbol":"P 4cw","operations":["+000+000+000","-000-000+006","0+0-0000+003","0-0+0000+009"]},{"hall":353,"number":79,"symbol":"I 4","operations":["+000+000+000","+000+000+666","-000-000+000","-000-000+666","0+0-0000+000","0+0-0000+666","0-0+0000+000","0-0+0000+666"]},{"hall":354,"number":80,"symbol":"I 4bw","operations":["+000+000+000","+000+000+666","-000-000+000","-000-000+666","0+0-0000+063","0+0-0000+609","0-0+0000+063","0-0+0000+609"]},{"hall":355,"number":81,"symbol":"P -4","operations":["+000+000+000","-000-000+000","0+0-0000-000","0-0+0000-000"]},{"hall":356,"number":82,"symbol":"I -4","operations":["+000+000+000","+000+000+666","-000-000+000","-000-000+666","0+0-0000-000","0+0-0000-666","0-0+0000-000","0-0+0000-666"]},{"hall":357,"number":83,"symbol":"-P 4","operations":["+000+000+000","+000+000-000","-000-000+000","-000-000-000","0+0-0000+000","0+0-0000-000","0-0+0000+000","0-0+0000-000"]},{"hall":358,"number":84,"symbol":"-P 4c","operations":["+000+000+000","+000+000-000","-000-000+000","-000-000-000","0+0-0000+006","0+0-0000-006","0-0+0000+006","0-0+0000-006"]},{"hall":359,"number":85,"symbol":"P 4ab -1ab","operations":["+000+000+000","+000+000-660","-000-000+000","-000-000-660","0+0-0000+660","0+0-0000-000","0-0+0000+660","0-0+0000-000"]},{"hall":360,"number":85,"symbol":"-P 4a","operations":["+000+000+000","+000+000-660","-000-000+660","-000-000-000","0+0-0000+060","0+0-0000-600","0-0+0000+600","0-0+0000-060"]},{"hall":361,"number":86,"symbol":"P 4n -1n","operations":["+000+000+000","+000+000-666","-000-000+000","-000-000-666","0+0-0000+666","0+0-0000-000","0-0+0000+666","0-0+0000-000"]},{"hall":362,"number":86,"symbol":"-P 4bc","operations":["+000+000+000","+000+000-660","-000-000+660","-000-000-000","0+0-0000+606","0+0-0000-066","0-0+0000+066","0-0+0000-606"]},{"hall":363,"number":87,"symbol":"-I 4","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","-000-000+000","-000-000+666","-000-000-000","-000-000-666","0+0-0000+000","0+0-0000+666","0+0-0000-000","0+0-0000-666","0-0+0000+000","0-0+0000+666","0-0+0000-000","0-0+0000-666"]},{"hall":364,"number":88,"symbol":"I 4bw -1bw","operations":["+000+000+000","+000+000+666","+000+000-063","+000+000-609","-000-000+000","-000-000+666","-000-000-063","-000-000-609","0+0-0000+063","0+0-0000+609","0+0-0000-000","0+0-0000-666","0-0+0000+063","0-0+0000+609","0-0+0000-000","0-0+0000-666"]},{"hall":365,"number":88,"symbol":"-I 4ad","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","-000-000+060","-000-000+606","-000-000-000","-000-000-666","0+0-0000+333","0+0-0000+999","0+0-0000-399","0+0-0000-933","0-0+0000+399","0-0+0000+933","0-0+0000-333","0-0+0000-999"]},{"hall":366,"number":89,"symbol":"P 4 2","operations":["+000+000+000","+000-000-000","-000+000-000","-000-000+000","0+0+0000-000","0+0-0000+000","0-0+0000+000","0-0-0000-000"]},{"hall":367,"number":90,"symbol":"P 4ab 2ab","operations":["+000+000+000","+000-000-660","-000+000-660","-000-000+000","0+0+0000-000","0+0-0000+660","0-0+0000+660","0-0-0000-000"]},{"hall":368,"number":91,"symbol":"P 4w 2c","operations":["+000+000+000","+000-000-006","-000+000-000","-000-000+006","0+0+0000-009","0+0-0000+009","0-0+0000+003","0-0-0000-003"]},{"hall":369,"number":92,"symbol":"P 4abw 2nw","operations":["+000+000+000","+000-000-669","-000+000-663","-000-000+006","0+0+0000-000","0+0-0000+669","0-0+0000+663","0-0-0000-006"]},{"hall":370,"number":93,"symbol":"P 4c 2","operations":["+000+000+000","+000-000-000","-000+000-000","-000-000+000","0+0+0000-006","0+0-0000+006","0-0+0000+006","0-0-0000-006"]},{"hall":371,"number":94,"symbol":"P 4n 2n","operations":["+000+000+000","+000-000-666","-000+000-666","-000-000+000","0+0+0000-000","0+0-0000+666","0-0+0000+666","0-0-0000-000"]},{"hall":372,"number":95,"symbol":"P 4cw 2c","operations":["+000+000+000","+000-000-006","-000+000-000","-000-000+006","0+0+0000-003","0+0-0000+003","0-0+0000+009","0-0-0000-009"]},{"hall":373,"number":96,"symbol":"P 4nw 2abw","operations":["+000+000+000","+000-000-663","-000+000-669","-000-000+006","0+0+0000-000","0+0-0000+663","0-0+0000+669","0-0-0000-006"]},{"hall":374,"number":97,"symbol":"I 4 2","operations":["+000+000+000","+000+000+666","+000-000-000","+000-000-666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","0+0+0000-000","0+0+0000-666","0+0-0000+000","0+0-0000+666","0-0+0000+000","0-0+0000+666","0-0-0000-000","0-0-0000-666"]},{"hall":375,"number":98,"symbol":"I 4bw 2bw","operations":["+000+000+000","+000+000+666","+000-000-063","+000-000-609","-000+000-063","-000+000-609","-000-000+000","-000-000+666","0+0+0000-000","0+0+0000-666","0+0-0000+063","0+0-0000+609","0-0+0000+063","0-0+0000+609","0-0-0000-000","0-0-0000-666"]},{"hall":376,"number":99,"symbol":"P 4 -2","operations":["+000+000+000","+000-000+000","-000+000+000","-000-000+000","0+0+0000+000","0+0-0000+000","0-0+0000+000","0-0-0000+000"]},{"hall":377,"number":100,"symbol":"P 4 -2ab","operations":["+000+000+000","+000-000+660","-000+000+660","-000-000+000","0+0+0000+660","0+0-0000+000","0-0+0000+000","0-0-0000+660"]},{"hall":378,"number":101,"symbol":"P 4c -2c","operations":["+000+000+000","+000-000+006","-000+000+006","-000-000+000","0+0+0000+000","0+0-0000+006","0-0+0000+006","0-0-0000+000"]},{"hall":379,"number":102,"symbol":"P 4n -2n","operations":["+000+000+000","+000-000+666","-000+000+666","-000-000+000","0+0+0000+000","0+0-0000+666","0-0+0000+666","0-0-0000+000"]},{"hall":380,"number":103,"symbol":"P 4 -2c","operations":["+000+000+000","+000-000+006","-000+000+006","-000-000+000","0+0+0000+006","0+0-0000+000","0-0+0000+000","0-0-0000+006"]},{"hall":381,"number":104,"symbol":"P 4 -2n","operations":["+000+000+000","+000-000+666","-000+000+666","-000-000+000","0+0+0000+666","0+0-0000+000","0-0+0000+000","0-0-0000+666"]},{"hall":382,"number":105,"symbol":"P 4c -2","operations":["+000+000+000","+000-000+000","-000+000+000","-000-000+000","0+0+0000+006","0+0-0000+006","0-0+0000+006","0-0-0000+006"]},{"hall":383,"number":106,"symbol":"P 4c -2ab","operations":["+000+000+000","+000-000+660","-000+000+660","-000-000+000","0+0+0000+666","0+0-0000+006","0-0+0000+006","0-0-0000+666"]},{"hall":384,"number":107,"symbol":"I 4 -2","operations":["+000+000+000","+000+000+666","+000-000+000","+000-000+666","-000+000+000","-000+000+666","-000-000+000","-000-000+666","0+0+0000+000","0+0+0000+666","0+0-0000+000","0+0-0000+666","0-0+0000+000","0-0+0000+666","0-0-0000+000","0-0-0000+666"]},{"hall":385,"number":108,"symbol":"I 4 -2c","operations":["+000+000+000","+000+000+666","+000-000+006","+000-000+660","-000+000+006","-000+000+660","-000-000+000","-000-000+666","0+0+0000+006","0+0+0000+660","0+0-0000+000","0+0-0000+666","0-0+0000+000","0-0+0000+666","0-0-0000+006","0-0-0000+660"]},{"hall":386,"number":109,"symbol":"I 4bw -2","operations":["+000+000+000","+000+000+666","+000-000+000","+000-000+666","-000+000+000","-000+000+666","-000-000+000","-000-000+666","0+0+0000+063","0+0+0000+609","0+0-0000+063","0+0-0000+609","0-0+0000+063","0-0+0000+609","0-0-0000+063","0-0-0000+609"]},{"hall":387,"number":110,"symbol":"I 4bw -2c","operations":["+000+000+000","+000+000+666","+000-000+006","+000-000+660","-000+000+006","-000+000+660","-000-000+000","-000-000+666","0+0+0000+069","0+0+0000+603","0+0-0000+063","0+0-0000+609","0-0+0000+063","0-0+0000+609","0-0-0000+069","0-0-0000+603"]},{"hall":388,"number":111,"symbol":"P -4 2","operations":["+000+000+000","+000-000-000","-000+000-000","-000-000+000","0+0+0000+000","0+0-0000-000","0-0+0000-000","0-0-0000+000"]},{"hall":389,"number":112,"symbol":"P -4 2c","operations":["+000+000+000","+000-000-006","-000+000-006","-000-000+000","0+0+0000+006","0+0-0000-000","0-0+0000-000","0-0-0000+006"]},{"hall":390,"number":113,"symbol":"P -4 2ab","operations":["+000+000+000","+000-000-660","-000+000-660","-000-000+000","0+0+0000+660","0+0-0000-000","0-0+0000-000","0-0-0000+660"]},{"hall":391,"number":114,"symbol":"P -4 2n","operations":["+000+000+000","+000-000-666","-000+000-666","-000-000+000","0+0+0000+666","0+0-0000-000","0-0+0000-000","0-0-0000+666"]},{"hall":392,"number":115,"symbol":"P -4 -2","operations":["+000+000+000","+000-000+000","-000+000+000","-000-000+000","0+0+0000-000","0+0-0000-000","0-0+0000-000","0-0-0000-000"]},{"hall":393,"number":116,"symbol":"P -4 -2c","operations":["+000+000+000","+000-000+006","-000+000+006","-000-000+000","0+0+0000-006","0+0-0000-000","0-0+0000-000","0-0-0000-006"]},{"hall":394,"number":117,"symbol":"P -4 -2ab","operations":["+000+000+000","+000-000+660","-000+000+660","-000-000+000","0+0+0000-660","0+0-0000-000","0-0+0000-000","0-0-0000-660"]},{"hall":395,"number":118,"symbol":"P -4 -2n","operations":["+000+000+000","+000-000+666","-000+000+666","-000-000+000","0+0+0000-666","0+0-0000-000","0-0+0000-000","0-0-0000-666"]},{"hall":396,"number":119,"symbol":"I -4 -2","operations":["+000+000+000","+000+000+666","+000-000+000","+000-000+666","-000+000+000","-000+000+666","-000-000+000","-000-000+666","0+0+0000-000","0+0+0000-666","0+0-0000-000","0+0-0000-666","0-0+0000-000","0-0+0000-666","0-0-0000-000","0-0-0000-666"]},{"hall":397,"number":120,"symbol":"I -4 -2c","operations":["+000+000+000","+000+000+666","+000-000+006","+000-000+660","-000+000+006","-000+000+660","-000-000+000","-000-000+666","0+0+0000-006","0+0+0000-660","0+0-0000-000","0+0-0000-666","0-0+0000-000","0-0+0000-666","0-0-0000-006","0-0-0000-660"]},{"hall":398,"number":121,"symbol":"I -4 2","operations":["+000+000+000","+000+000+666","+000-000-000","+000-000-666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","0+0+0000+000","0+0+0000+666","0+0-0000-000","0+0-0000-666","0-0+0000-000","0-0+0000-666","0-0-0000+000","0-0-0000+666"]},{"hall":399,"number":122,"symbol":"I -4 2bw","operations":["+000+000+000","+000+000+666","+000-000-063","+000-000-609","-000+000-063","-000+000-609","-000-000+000","-000-000+666","0+0+0000+063","0+0+0000+609","0+0-0000-000","0+0-0000-666","0-0+0000-000","0-0+0000-666","0-0-0000+063","0-0-0000+609"]},{"hall":400,"number":123,"symbol":"-P 4 2","operations":["+000+000+000","+000+000-000","+000-000+000","+000-000-000","-000+000+000","-000+000-000","-000-000+000","-000-000-000","0+0+0000+000","0+0+0000-000","0+0-0000+000","0+0-0000-000","0-0+0000+000","0-0+0000-000","0-0-0000+000","0-0-0000-000"]},{"hall":401,"number":124,"symbol":"-P 4 2c","operations":["+000+000+000","+000+000-000","+000-000+006","+000-000-006","-000+000+006","-000+000-006","-000-000+000","-000-000-000","0+0+0000+006","0+0+0000-006","0+0-0000+000","0+0-0000-000","0-0+0000+000","0-0+0000-000","0-0-0000+006","0-0-0000-006"]},{"hall":402,"number":125,"symbol":"P 4 2 -1ab","operations":["+000+000+000","+000+000-660","+000-000+660","+000-000-000","-000+000+660","-000+000-000","-000-000+000","-000-000-660","0+0+0000+660","0+0+0000-000","0+0-0000+000","0+0-0000-660","0-0+0000+000","0-0+0000-660","0-0-0000+660","0-0-0000-000"]},{"hall":403,"number":125,"symbol":"-P 4a 2b","operations":["+000+000+000","+000+000-660","+000-000+600","+000-000-060","-000+000+060","-000+000-600","-000-000+660","-000-000-000","0+0+0000+660","0+0+0000-000","0+0-0000+060","0+0-0000-600","0-0+0000+600","0-0+0000-060","0-0-0000+000","0-0-0000-660"]},{"hall":404,"number":126,"symbol":"P 4 2 -1n","operations":["+000+000+000","+000+000-666","+000-000+666","+000-000-000","-000+000+666","-000+000-000","-000-000+000","-000-000-666","0+0+0000+666","0+0+0000-000","0+0-0000+000","0+0-0000-666","0-0+0000+000","0-0+0000-666","0-0-0000+666","0-0-0000-000"]},{"hall":405,"number":126,"symbol":"-P 4a 2bc","operations":["+000+000+000","+000+000-660","+000-000+606","+000-000-066","-000+000+066","-000+000-606","-000-000+660","-000-000-000","0+0+0000+666","0+0+0000-006","0+0-0000+060","0+0-0000-600","0-0+0000+600","0-0+0000-060","0-0-0000+006","0-0-0000-666"]},{"hall":406,"number":127,"symbol":"-P 4 2ab","operations":["+000+000+000","+000+000-000","+000-000+660","+000-000-660","-000+000+660","-000+000-660","-000-000+000","-000-000-000","0+0+0000+660","0+0+0000-660","0+0-0000+000","0+0-0000-000","0-0+0000+000","0-0+0000-000","0-0-0000+660","0-0-0000-660"]},{"hall":407,"number":128,"symbol":"-P 4 2n","operations":["+000+000+000","+000+000-000","+000-000+666","+000-000-666","-000+000+666","-000+000-666","-000-000+000","-000-000-000","0+0+0000+666","0+0+0000-666","0+0-0000+000","0+0-0000-000","0-0+0000+000","0-0+0000-000","0-0-0000+666","0-0-0000-666"]},{"hall":408,"number":129,"symbol":"P 4ab 2ab -1ab","operations":["+000+000+000","+000+000-660","+000-000+000","+000-000-660","-000+000+000","-000+000-660","-000-000+000","-000-000-660","0+0+0000+660","0+0+0000-000","0+0-0000+660","0+0-0000-000","0-0+0000+660","0-0+0000-000","0-0-0000+660","0-0-0000-000"]},{"hall":409,"number":129,"symbol":"-P 4a 2a","operations":["+000+000+000","+000+000-660","+000-000+060","+000-000-600","-000+000+600","-000+000-060","-000-000+660","-000-000-000","0+0+0000+000","0+0+0000-660","0+0-0000+060","0+0-0000-600","0-0+0000+600","0-0+0000-060","0-0-0000+660","0-0-0000-000"]},{"hall":410,"number":130,"symbol":"P 4ab 2n -1ab","operations":["+000+000+000","+000+000-660","+000-000+006","+000-000-666","-000+000+006","-000+000-666","-000-000+000","-000-000-660","0+0+0000+666","0+0+0000-006","0+0-0000+660","0+0-0000-000","0-0+0000+660","0-0+0000-000","0-0-0000+666","0-0-0000-006"]},{"hall":411,"number":130,"symbol":"-P 4a 2ac","operations":["+000+000+000","+000+000-660","+000-000+066","+000-000-606","-000+000+606","-000+000-066","-000-000+660","-000-000-000","0+0+0000+006","0+0+0000-666","0+0-0000+060","0+0-0000-600","0-0+0000+600","0-0+0000-060","0-0-0000+666","0-0-0000-006"]},{"hall":412,"number":131,"symbol":"-P 4c 2","operations":["+000+000+000","+000+000-000","+000-000+000","+000-000-000","-000+000+000","-000+000-000","-000-000+000","-000-000-000","0+0+0000+006","0+0+0000-006","0+0-0000+006","0+0-0000-006","0-0+0000+006","0-0+0000-006","0-0-0000+006","0-0-0000-006"]},{"hall":413,"number":132,"symbol":"-P 4c 2c","operations":["+000+000+000","+000+000-000","+000-000+006","+000-000-006","-000+000+006","-000+000-006","-000-000+000","-000-000-000","0+0+0000+000","0+0+0000-000","0+0-0000+006","0+0-0000-006","0-0+0000+006","0-0+0000-006","0-0-0000+000","0-0-0000-000"]},{"hall":414,"number":133,"symbol":"P 4n 2c -1n","operations":["+000+000+000","+000+000-666","+000-000+660","+000-000-006","-000+000+660","-000+000-006","-000-000+000","-000-000-666","0+0+0000+006","0+0+0000-660","0+0-0000+666","0+0-0000-000","0-0+0000+666","0-0+0000-000","0-0-0000+006","0-0-0000-660"]},{"hall":415,"number":133,"symbol":"-P 4ac 2b","operations":["+000+000+000","+000+000-660","+000-000+600","+000-000-060","-000+000+060","-000+000-600","-000-000+660","-000-000-000","0+0+0000+666","0+0+0000-006","0+0-0000+066","0+0-0000-606","0-0+0000+606","0-0+0000-066","0-0-0000+006","0-0-0000-666"]},{"hall":416,"number":134,"symbol":"P 4n 2 -1n","operations":["+000+000+000","+000+000-666","+000-000+666","+000-000-000","-000+000+666","-000+000-000","-000-000+000","-000-000-666","0+0+0000+000","0+0+0000-666","0+0-0000+666","0+0-0000-000","0-0+0000+666","0-0+0000-000","0-0-0000+000","0-0-0000-666"]},{"hall":417,"number":134,"symbol":"-P 4ac 2bc","operations":["+000+000+000","+000+000-660","+000-000+606","+000-000-066","-000+000+066","-000+000-606","-000-000+660","-000-000-000","0+0+0000+660","0+0+0000-000","0+0-0000+066","0+0-0000-606","0-0+0000+606","0-0+0000-066","0-0-0000+000","0-0-0000-660"]},{"hall":418,"number":135,"symbol":"-P 4c 2ab","operations":["+000+000+000","+000+000-000","+000-000+660","+000-000-660","-000+000+660","-000+000-660","-000-000+000","-000-000-000","0+0+0000+666","0+0+0000-666","0+0-0000+006","0+0-0000-006","0-0+0000+006","0-0+0000-006","0-0-0000+666","0-0-0000-666"]},{"hall":419,"number":136,"symbol":"-P 4n 2n","operations":["+000+000+000","+000+000-000","+000-000+666","+000-000-666","-000+000+666","-000+000-666","-000-000+000","-000-000-000","0+0+0000+000","0+0+0000-000","0+0-0000+666","0+0-0000-666","0-0+0000+666","0-0+0000-666","0-0-0000+000","0-0-0000-000"]},{"hall":420,"number":137,"symbol":"P 4n 2n -1n","operations":["+000+000+000","+000+000-666","+000-000+000","+000-000-666","-000+000+000","-000+000-666","-000-000+000","-000-000-666","0+0+0000+666","0+0+0000-000","0+0-0000+666","0+0-0000-000","0-0+0000+666","0-0+0000-000","0-0-0000+666","0-0-0000-000"]},{"hall":421,"number":137,"symbol":"-P 4ac 2a","operations":["+000+000+000","+000+000-660","+000-000+060","+000-000-600","-000+000+600","-000+000-060","-000-000+660","-000-000-000","0+0+0000+006","0+0+0000-666","0+0-0000+066","0+0-0000-606","0-0+0000+606","0-0+0000-066","0-0-0000+666","0-0-0000-006"]},{"hall":422,"number":138,"symbol":"P 4n 2ab -1n","operations":["+000+000+000","+000+000-666","+000-000+006","+000-000-660","-000+000+006","-000+000-660","-000-000+000","-000-000-666","0+0+0000+660","0+0+0000-006","0+0-0000+666","0+0-0000-000","0-0+0000+666","0-0+0000-000","0-0-0000+660","0-0-0000-006"]},{"hall":423,"number":138,"symbol":"-P 4ac 2ac","operations":["+000+000+000","+000+000-660","+000-000+066","+000-000-606","-000+000+606","-000+000-066","-000-000+660","-000-000-000","0+0+0000+000","0+0+0000-660","0+0-0000+066","0+0-0000-606","0-0+0000+606","0-0+0000-066","0-0-0000+660","0-0-0000-000"]},{"hall":424,"number":139,"symbol":"-I 4 2","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+000","+000-000+666","+000-000-000","+000-000-666","-000+000+000","-000+000+666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","-000-000-000","-000-000-666","0+0+0000+000","0+0+0000+666","0+0+0000-000","0+0+0000-666","0+0-0000+000","0+0-0000+666","0+0-0000-000","0+0-0000-666","0-0+0000+000","0-0+0000+666","0-0+0000-000","0-0+0000-666","0-0-0000+000","0-0-0000+666","0-0-0000-000","0-0-0000-666"]},{"hall":425,"number":140,"symbol":"-I 4 2c","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+006","+000-000+660","+000-000-006","+000-000-660","-000+000+006","-000+000+660","-000+000-006","-000+000-660","-000-000+000","-000-000+666","-000-000-000","-000-000-666","0+0+0000+006","0+0+0000+660","0+0+0000-006","0+0+0000-660","0+0-0000+000","0+0-0000+666","0+0-0000-000","0+0-0000-666","0-0+0000+000","0-0+0000+666","0-0+0000-000","0-0+0000-666","0-0-0000+006","0-0-0000+660","0-0-0000-006","0-0-0000-660"]},{"hall":426,"number":141,"symbol":"I 4bw 2bw -1bw","operations":["+000+000+000","+000+000+666","+000+000-063","+000+000-609","+000-000+000","+000-000+666","+000-000-063","+000-000-609","-000+000+000","-000+000+666","-000+000-063","-000+000-609","-000-000+000","-000-000+666","-000-000-063","-000-000-609","0+0+0000+063","0+0+0000+609","0+0+0000-000","0+0+0000-666","0+0-0000+063","0+0-0000+609","0+0-0000-000","0+0-0000-666","0-0+0000+063","0-0+0000+609","0-0+0000-000","0-0+0000-666","0-0-0000+063","0-0-0000+609","0-0-0000-000","0-0-0000-666"]},{"hall":427,"number":141,"symbol":"-I 4bd 2","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","+000-000+060","+000-000+606","+000-000-000","+000-000-666","-000+000+000","-000+000+666","-000+000-060","-000+000-606","-000-000+060","-000-000+606","-000-000-000","-000-000-666","0+0+0000+339","0+0+0000+993","0+0+0000-393","0+0+0000-939","0+0-0000+339","0+0-0000+993","0+0-0000-393","0+0-0000-939","0-0+0000+393","0-0+0000+939","0-0+0000-339","0-0+0000-993","0-0-0000+393","0-0-0000+939","0-0-0000-339","0-0-0000-993"]},{"hall":428,"number":142,"symbol":"I 4bw 2aw -1bw","operations":["+000+000+000","+000+000+666","+000+000-063","+000+000-609","+000-000+006","+000-000+660","+000-000-069","+000-000-603","-000+000+006","-000+000+660","-000+000-069","-000+000-603","-000-000+000","-000-000+666","-000-000-063","-000-000-609","0+0+0000+069","0+0+0000+603","0+0+0000-006","0+0+0000-660","0+0-0000+063","0+0-0000+609","0+0-0000-000","0+0-0000-666","0-0+0000+063","0-0+0000+609","0-0+0000-000","0-0+0000-666","0-0-0000+069","0-0-0000+603","0-0-0000-006","0-0-0000-660"]},{"hall":429,"number":142,"symbol":"-I 4bd 2c","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","+000-000+066","+000-000+600","+000-000-006","+000-000-660","-000+000+006","-000+000+660","-000+000-066","-000+000-600","-000-000+060","-000-000+606","-000-000-000","-000-000-666","0+0+0000+333","0+0+0000+999","0+0+0000-399","0+0+0000-933","0+0-0000+339","0+0-0000+993","0+0-0000-393","0+0-0000-939","0-0+0000+393","0-0+0000+939","0-0+0000-339","0-0+0000-993","0-0-0000+399","0-0-0000+933","0-0-0000-333","0-0-0000-999"]},{"hall":430,"number":143,"symbol":"P 3","operations":["+000+000+000","-+0-0000+000","0-0+-000+000"]},{"hall":431,"number":144,"symbol":"P 31","operations":["+000+000+000","-+0-0000+008","0-0+-000+004"]},{"hall":432,"number":145,"symbol":"P 32","operations":["+000+000+000","-+0-0000+004","0-0+-000+008"]},{"hall":433,"number":146,"symbol":"R 3","operations":["+000+000+000","+000+000+488","+000+000+844","-+0-0000+000","-+0-0000+488","-+0-0000+844","0-0+-000+000","0-0+-000+488","0-0+-000+844"]},{"hall":434,"number":146,"symbol":"P 3*","operations":["+000+000+000","0+000++00000","00++000+0000"]},{"hall":435,"number":147,"symbol":"-P 3","operations":["+-0+0000-000","+000+000+000","-+0-0000+000","-000-000-000","0+0-+000-000","0-0+-000+000"]},{"hall":436,"number":148,"symbol":"-R 3","operations":["+-0+0000-000","+-0+0000-488","+-0+0000-844","+000+000+000","+000+000+488","+000+000+844","-+0-0000+000","-+0-0000+488","-+0-0000+844","-000-000-000","-000-000-488","-000-000-844","0+0-+000-000","0+0-+000-488","0+0-+000-844","0-0+-000+000","0-0+-000+488","0-0+-000+844"]},{"hall":437,"number":148,"symbol":"-P 3*","operations":["+000+000+000","-000-000-000","0+000++00000","0-000--00000","00++000+0000","00--000-0000"]},{"hall":438,"number":149,"symbol":"P 3 2","operations":["+00+-000-000","+000+000+000","-+0-0000+000","-+00+000-000","0-0+-000+000","0-0-0000-000"]},{"hall":439,"number":150,"symbol":"P 3 2\"","operations":["+-00-000-000","+000+000+000","-+0-0000+000","-00-+000-000","0+0+0000-000","0-0+-000+000"]},{"hall":440,"number":151,"symbol":"P 31 2 (0 0 4)","operations":["+00+-000-000","+000+000+000","-+0-0000+008","-+00+000-004","0-0+-000+004","0-0-0000-008"]},{"hall":441,"number":152,"symbol":"P 31 2\"","operations":["+-00-000-008","+000+000+000","-+0-0000+008","-00-+000-004","0+0+0000-000","0-0+-000+004"]},{"hall":442,"number":153,"symbol":"P 32 2 (0 0 2)","operations":["+00+-000-000","+000+000+000","-+0-0000+004","-+00+000-008","0-0+-000+008","0-0-0000-004"]},{"hall":443,"number":154,"symbol":"P 32 2\"","operations":["+-00-000-004","+000+000+000","-+0-0000+004","-00-+000-008","0+0+0000-000","0-0+-000+008"]},{"hall":444,"number":155,"symbol":"R 3 2\"","operations":["+-00-000-000","+-00-000-488","+-00-000-844","+000+000+000","+000+000+488","+000+000+844","-+0-0000+000","-+0-0000+488","-+0-0000+844","-00-+000-000","-00-+000-488","-00-+000-844","0+0+0000-000","0+0+0000-488","0+0+0000-844","0-0+-000+000","0-0+-000+488","0-0+-000+844"]},{"hall":445,"number":155,"symbol":"P 3* 2","operations":["+000+000+000","-0000-0-0000","0+000++00000","0-0-0000-000","00++000+0000","00-0-0-00000"]},{"hall":446,"number":156,"symbol":"P 3 -2\"","operations":["+00+-000+000","+000+000+000","-+0-0000+000","-+00+000+000","0-0+-000+000","0-0-0000+000"]},{"hall":447,"number":157,"symbol":"P 3 -2","operations":["+-00-000+000","+000+000+000","-+0-0000+000","-00-+000+000","0+0+0000+000","0-0+-000+000"]},{"hall":448,"number":158,"symbol":"P 3 -2\"c","operations":["+00+-000+006","+000+000+000","-+0-0000+000","-+00+000+006","0-0+-000+000","0-0-0000+006"]},{"hall":449,"number":159,"symbol":"P 3 -2c","operations":["+-00-000+006","+000+000+000","-+0-0000+000","-00-+000+006","0+0+0000+006","0-0+-000+000"]},{"hall":450,"number":160,"symbol":"R 3 -2\"","operations":["+00+-000+000","+00+-000+488","+00+-000+844","+000+000+000","+000+000+488","+000+000+844","-+0-0000+000","-+0-0000+488","-+0-0000+844","-+00+000+000","-+00+000+488","-+00+000+844","0-0+-000+000","0-0+-000+488","0-0+-000+844","0-0-0000+000","0-0-0000+488","0-0-0000+844"]},{"hall":451,"number":160,"symbol":"P 3* -2","operations":["+000+000+000","+0000+0+0000","0+0+0000+000","0+000++00000","00++000+0000","00+0+0+00000"]},{"hall":452,"number":161,"symbol":"R 3 -2\"c","operations":["+00+-000+006","+00+-000+482","+00+-000+84a","+000+000+000","+000+000+488","+000+000+844","-+0-0000+000","-+0-0000+488","-+0-0000+844","-+00+000+006","-+00+000+482","-+00+000+84a","0-0+-000+000","0-0+-000+488","0-0+-000+844","0-0-0000+006","0-0-0000+482","0-0-0000+84a"]},{"hall":453,"number":161,"symbol":"P 3* -2n","operations":["+000+000+000","+0000+0+0666","0+0+0000+666","0+000++00000","00++000+0000","00+0+0+00666"]},{"hall":454,"number":162,"symbol":"-P 3 2","operations":["+-0+0000-000","+-00-000+000","+00+-000-000","+000+000+000","-+0-0000+000","-+00+000-000","-00-+000+000","-000-000-000","0+0+0000+000","0+0-+000-000","0-0+-000+000","0-0-0000-000"]},{"hall":455,"number":163,"symbol":"-P 3 2c","operations":["+-0+0000-000","+-00-000+006","+00+-000-006","+000+000+000","-+0-0000+000","-+00+000-006","-00-+000+006","-000-000-000","0+0+0000+006","0+0-+000-000","0-0+-000+000","0-0-0000-006"]},{"hall":456,"number":164,"symbol":"-P 3 2\"","operations":["+-0+0000-000","+-00-000-000","+00+-000+000","+000+000+000","-+0-0000+000","-+00+000+000","-00-+000-000","-000-000-000","0+0+0000-000","0+0-+000-000","0-0+-000+000","0-0-0000+000"]},{"hall":457,"number":165,"symbol":"-P 3 2\"c","operations":["+-0+0000-000","+-00-000-006","+00+-000+006","+000+000+000","-+0-0000+000","-+00+000+006","-00-+000-006","-000-000-000","0+0+0000-006","0+0-+000-000","0-0+-000+000","0-0-0000+006"]},{"hall":458,"number":166,"symbol":"-R 3 2\"","operations":["+-0+0000-000","+-0+0000-488","+-0+0000-844","+-00-000-000","+-00-000-488","+-00-000-844","+00+-000+000","+00+-000+488","+00+-000+844","+000+000+000","+000+000+488","+000+000+844","-+0-0000+000","-+0-0000+488","-+0-0000+844","-+00+000+000","-+00+000+488","-+00+000+844","-00-+000-000","-00-+000-488","-00-+000-844","-000-000-000","-000-000-488","-000-000-844","0+0+0000-000","0+0+0000-488","0+0+0000-844","0+0-+000-000","0+0-+000-488","0+0-+000-844","0-0+-000+000","0-0+-000+488","0-0+-000+844","0-0-0000+000","0-0-0000+488","0-0-0000+844"]},{"hall":459,"number":166,"symbol":"-P 3* 2","operations":["+000+000+000","+0000+0+0000","-000-000-000","-0000-0-0000","0+0+0000+000","0+000++00000","0-0-0000-000","0-000--00000","00++000+0000","00+0+0+00000","00--000-0000","00-0-0-00000"]},{"hall":460,"number":167,"symbol":"-R 3 2\"c","operations":["+-0+0000-000","+-0+0000-488","+-0+0000-844","+-00-000-006","+-00-000-482","+-00-000-84a","+00+-000+006","+00+-000+482","+00+-000+84a","+000+000+000","+000+000+488","+000+000+844","-+0-0000+000","-+0-0000+488","-+0-0000+844","-+00+000+006","-+00+000+482","-+00+000+84a","-00-+000-006","-00-+000-482","-00-+000-84a","-000-000-000","-000-000-488","-000-000-844","0+0+0000-006","0+0+0000-482","0+0+0000-84a","0+0-+000-000","0+0-+000-488","0+0-+000-844","0-0+-000+000","0-0+-000+488","0-0+-000+844","0-0-0000+006","0-0-0000+482","0-0-0000+84a"]},{"hall":461,"number":167,"symbol":"-P 3* 2n","operations":["+000+000+000","+0000+0+0666","-000-000-000","-0000-0-0666","0+0+0000+666","0+000++00000","0-0-0000-666","0-000--00000","00++000+0000","00+0+0+00666","00--000-0000","00-0-0-00666"]},{"hall":462,"number":168,"symbol":"P 6","operations":["+-0+0000+000","+000+000+000","-+0-0000+000","-000-000+000","0+0-+000+000","0-0+-000+000"]},{"hall":463,"number":169,"symbol":"P 61","operations":["+-0+0000+002","+000+000+000","-+0-0000+008","-000-000+006","0+0-+000+00a","0-0+-000+004"]},{"hall":464,"number":170,"symbol":"P 65","operations":["+-0+0000+00a","+000+000+000","-+0-0000+004","-000-000+006","0+0-+000+002","0-0+-000+008"]},{"hall":465,"number":171,"symbol":"P 62","operations":["+-0+0000+004","+000+000+000","-+0-0000+004","-000-000+000","0+0-+000+008","0-0+-000+008"]},{"hall":466,"number":172,"symbol":"P 64","operations":["+-0+0000+008","+000+000+000","-+0-0000+008","-000-000+000","0+0-+000+004","0-0+-000+004"]},{"hall":467,"number":173,"symbol":"P 6c","operations":["+-0+0000+006","+000+000+000","-+0-0000+000","-000-000+006","0+0-+000+006","0-0+-000+000"]},{"hall":468,"number":174,"symbol":"P -6","operations":["+000+000+000","+000+000-000","-+0-0000+000","-+0-0000-000","0-0+-000+000","0-0+-000-000"]},{"hall":469,"number":175,"symbol":"-P 6","operations":["+-0+0000+000","+-0+0000-000","+000+000+000","+000+000-000","-+0-0000+000","-+0-0000-000","-000-000+000","-000-000-000","0+0-+000+000","0+0-+000-000","0-0+-000+000","0-0+-000-000"]},{"hall":470,"number":176,"symbol":"-P 6c","operations":["+-0+0000+006","+-0+0000-000","+000+000+000","+000+000-006","-+0-0000+000","-+0-0000-006","-000-000+006","-000-000-000","0+0-+000+006","0+0-+000-000","0-0+-000+000","0-0+-000-006"]},{"hall":471,"number":177,"symbol":"P 6 2","operations":["+-0+0000+000","+-00-000-000","+00+-000-000","+000+000+000","-+0-0000+000","-+00+000-000","-00-+000-000","-000-000+000","0+0+0000-000","0+0-+000+000","0-0+-000+000","0-0-0000-000"]},{"hall":472,"number":178,"symbol":"P 61 2 (0 0 5)","operations":["+-0+0000+002","+-00-000-000","+00+-000-002","+000+000+000","-+0-0000+008","-+00+000-006","-00-+000-008","-000-000+006","0+0+0000-004","0+0-+000+00a","0-0+-000+004","0-0-0000-00a"]},{"hall":473,"number":179,"symbol":"P 65 2 (0 0 1)","operations":["+-0+0000+00a","+-00-000-000","+00+-000-00a","+000+000+000","-+0-0000+004","-+00+000-006","-00-+000-004","-000-000+006","0+0+0000-008","0+0-+000+002","0-0+-000+008","0-0-0000-002"]},{"hall":474,"number":180,"symbol":"P 62 2 (0 0 4)","operations":["+-0+0000+004","+-00-000-000","+00+-000-004","+000+000+000","-+0-0000+004","-+00+000-000","-00-+000-004","-000-000+000","0+0+0000-008","0+0-+000+008","0-0+-000+008","0-0-0000-008"]},{"hall":475,"number":181,"symbol":"P 64 2 (0 0 2)","operations":["+-0+0000+008","+-00-000-000","+00+-000-008","+000+000+000","-+0-0000+008","-+00+000-000","-00-+000-008","-000-000+000","0+0+0000-004","0+0-+000+004","0-0+-000+004","0-0-0000-004"]},{"hall":476,"number":182,"symbol":"P 6c 2c","operations":["+-0+0000+006","+-00-000-000","+00+-000-006","+000+000+000","-+0-0000+000","-+00+000-006","-00-+000-000","-000-000+006","0+0+0000-000","0+0-+000+006","0-0+-000+000","0-0-0000-006"]},{"hall":477,"number":183,"symbol":"P 6 -2","operations":["+-0+0000+000","+-00-000+000","+00+-000+000","+000+000+000","-+0-0000+000","-+00+000+000","-00-+000+000","-000-000+000","0+0+0000+000","0+0-+000+000","0-0+-000+000","0-0-0000+000"]},{"hall":478,"number":184,"symbol":"P 6 -2c","operations":["+-0+0000+000","+-00-000+006","+00+-000+006","+000+000+000","-+0-0000+000","-+00+000+006","-00-+000+006","-000-000+000","0+0+0000+006","0+0-+000+000","0-0+-000+000","0-0-0000+006"]},{"hall":479,"number":185,"symbol":"P 6c -2","operations":["+-0+0000+006","+-00-000+000","+00+-000+006","+000+000+000","-+0-0000+000","-+00+000+006","-00-+000+000","-000-000+006","0+0+0000+000","0+0-+000+006","0-0+-000+000","0-0-0000+006"]},{"hall":480,"number":186,"symbol":"P 6c -2c","operations":["+-0+0000+006","+-00-000+006","+00+-000+000","+000+000+000","-+0-0000+000","-+00+000+000","-00-+000+006","-000-000+006","0+0+0000+006","0+0-+000+006","0-0+-000+000","0-0-0000+000"]},{"hall":481,"number":187,"symbol":"P -6 2","operations":["+00+-000+000","+00+-000-000","+000+000+000","+000+000-000","-+0-0000+000","-+0-0000-000","-+00+000+000","-+00+000-000","0-0+-000+000","0-0+-000-000","0-0-0000+000","0-0-0000-000"]},{"hall":482,"number":188,"symbol":"P -6c 2","operations":["+00+-000+006","+00+-000-000","+000+000+000","+000+000-006","-+0-0000+000","-+0-0000-006","-+00+000+006","-+00+000-000","0-0+-000+000","0-0+-000-006","0-0-0000+006","0-0-0000-000"]},{"hall":483,"number":189,"symbol":"P -6 -2","operations":["+-00-000+000","+-00-000-000","+000+000+000","+000+000-000","-+0-0000+000","-+0-0000-000","-00-+000+000","-00-+000-000","0+0+0000+000","0+0+0000-000","0-0+-000+000","0-0+-000-000"]},{"hall":484,"number":190,"symbol":"P -6c -2c","operations":["+-00-000+006","+-00-000-000","+000+000+000","+000+000-006","-+0-0000+000","-+0-0000-006","-00-+000+006","-00-+000-000","0+0+0000+006","0+0+0000-000","0-0+-000+000","0-0+-000-006"]},{"hall":485,"number":191,"symbol":"-P 6 2","operations":["+-0+0000+000","+-0+0000-000","+-00-000+000","+-00-000-000","+00+-000+000","+00+-000-000","+000+000+000","+000+000-000","-+0-0000+000","-+0-0000-000","-+00+000+000","-+00+000-000","-00-+000+000","-00-+000-000","-000-000+000","-000-000-000","0+0+0000+000","0+0+0000-000","0+0-+000+000","0+0-+000-000","0-0+-000+000","0-0+-000-000","0-0-0000+000","0-0-0000-000"]},{"hall":486,"number":192,"symbol":"-P 6 2c","operations":["+-0+0000+000","+-0+0000-000","+-00-000+006","+-00-000-006","+00+-000+006","+00+-000-006","+000+000+000","+000+000-000","-+0-0000+000","-+0-0000-000","-+00+000+006","-+00+000-006","-00-+000+006","-00-+000-006","-000-000+000","-000-000-000","0+0+0000+006","0+0+0000-006","0+0-+000+000","0+0-+000-000","0-0+-000+000","0-0+-000-000","0-0-0000+006","0-0-0000-006"]},{"hall":487,"number":193,"symbol":"-P 6c 2","operations":["+-0+0000+006","+-0+0000-000","+-00-000+000","+-00-000-006","+00+-000+006","+00+-000-000","+000+000+000","+000+000-006","-+0-0000+000","-+0-0000-006","-+00+000+006","-+00+000-000","-00-+000+000","-00-+000-006","-000-000+006","-000-000-000","0+0+0000+000","0+0+0000-006","0+0-+000+006","0+0-+000-000","0-0+-000+000","0-0+-000-006","0-0-0000+006","0-0-0000-000"]},{"hall":488,"number":194,"symbol":"-P 6c 2c","operations":["+-0+0000+006","+-0+0000-000","+-00-000+006","+-00-000-000","+00+-000+000","+00+-000-006","+000+000+000","+000+000-006","-+0-0000+000","-+0-0000-006","-+00+000+000","-+00+000-006","-00-+000+006","-00-+000-000","-000-000+006","-000-000-000","0+0+0000+006","0+0+0000-000","0+0-+000+006","0+0-+000-000","0-0+-000+000","0-0+-000-006","0-0-0000+000","0-0-0000-006"]},{"hall":489,"number":195,"symbol":"P 2 2 3","operations":["+000+000+000","+000-000-000","-000+000-000","-000-000+000","0+000++00000","0+000--00000","0-000+-00000","0-000-+00000","00++000+0000","00+-000-0000","00-+000-0000","00--000+0000"]},{"hall":490,"number":196,"symbol":"F 2 2 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660"]},{"hall":491,"number":197,"symbol":"I 2 2 3","operations":["+000+000+000","+000+000+666","+000-000-000","+000-000-666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","0+000++00000","0+000++00666","0+000--00000","0+000--00666","0-000+-00000","0-000+-00666","0-000-+00000","0-000-+00666","00++000+0000","00++000+0666","00+-000-0000","00+-000-0666","00-+000-0000","00-+000-0666","00--000+0000","00--000+0666"]},{"hall":492,"number":198,"symbol":"P 2ac 2ab 3","operations":["+000+000+000","+000-000-660","-000+000-066","-000-000+606","0+000++00000","0+000--00660","0-000+-00066","0-000-+00606","00++000+0000","00+-000-0660","00-+000-0066","00--000+0606"]},{"hall":493,"number":199,"symbol":"I 2b 2c 3","operations":["+000+000+000","+000+000+666","+000-000-006","+000-000-660","-000+000-066","-000+000-600","-000-000+060","-000-000+606","0+000++00000","0+000++00666","0+000--00006","0+000--00660","0-000+-00066","0-000+-00600","0-000-+00060","0-000-+00606","00++000+0000","00++000+0666","00+-000-0006","00+-000-0660","00-+000-0066","00-+000-0600","00--000+0060","00--000+0606"]},{"hall":494,"number":200,"symbol":"-P 2 2 3","operations":["+000+000+000","+000+000-000","+000-000+000","+000-000-000","-000+000+000","-000+000-000","-000-000+000","-000-000-000","0+000++00000","0+000+-00000","0+000-+00000","0+000--00000","0-000++00000","0-000+-00000","0-000-+00000","0-000--00000","00++000+0000","00++000-0000","00+-000+0000","00+-000-0000","00-+000+0000","00-+000-0000","00--000+0000","00--000-0000"]},{"hall":495,"number":201,"symbol":"P 2 2 3 -1n","operations":["+000+000+000","+000+000-666","+000-000+666","+000-000-000","-000+000+666","-000+000-000","-000-000+000","-000-000-666","0+000++00000","0+000+-00666","0+000-+00666","0+000--00000","0-000++00666","0-000+-00000","0-000-+00000","0-000--00666","00++000+0000","00++000-0666","00+-000+0666","00+-000-0000","00-+000+0666","00-+000-0000","00--000+0000","00--000-0666"]},{"hall":496,"number":201,"symbol":"-P 2ab 2bc 3","operations":["+000+000+000","+000+000-660","+000-000+606","+000-000-066","-000+000+066","-000+000-606","-000-000+660","-000-000-000","0+000++00000","0+000+-00660","0+000-+00606","0+000--00066","0-000++00066","0-000+-00606","0-000-+00660","0-000--00000","00++000+0000","00++000-0660","00+-000+0606","00+-000-0066","00-+000+0066","00-+000-0606","00--000+0660","00--000-0000"]},{"hall":497,"number":202,"symbol":"-F 2 2 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-000","+000+000-066","+000+000-606","+000+000-660","+000-000+000","+000-000+066","+000-000+606","+000-000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","-000+000+000","-000+000+066","-000+000+606","-000+000+660","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-000-000-000","-000-000-066","-000-000-606","-000-000-660","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00000","0+000+-00066","0+000+-00606","0+000+-00660","0+000-+00000","0+000-+00066","0+000-+00606","0+000-+00660","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-000++00000","0-000++00066","0-000++00606","0-000++00660","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","0-000--00000","0-000--00066","0-000--00606","0-000--00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0000","00++000-0066","00++000-0606","00++000-0660","00+-000+0000","00+-000+0066","00+-000+0606","00+-000+0660","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00-+000+0000","00-+000+0066","00-+000+0606","00-+000+0660","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00--000-0000","00--000-0066","00--000-0606","00--000-0660"]},{"hall":498,"number":203,"symbol":"F 2 2 3 -1d","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-333","+000+000-399","+000+000-939","+000+000-993","+000-000+333","+000-000+399","+000-000+939","+000-000+993","+000-000-000","+000-000-066","+000-000-606","+000-000-660","-000+000+333","-000+000+399","-000+000+939","-000+000+993","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-000-000-333","-000-000-399","-000-000-939","-000-000-993","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00333","0+000+-00399","0+000+-00939","0+000+-00993","0+000-+00333","0+000-+00399","0+000-+00939","0+000-+00993","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-000++00333","0-000++00399","0-000++00939","0-000++00993","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","0-000--00333","0-000--00399","0-000--00939","0-000--00993","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0333","00++000-0399","00++000-0939","00++000-0993","00+-000+0333","00+-000+0399","00+-000+0939","00+-000+0993","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00-+000+0333","00-+000+0399","00-+000+0939","00-+000+0993","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00--000-0333","00--000-0399","00--000-0939","00--000-0993"]},{"hall":499,"number":203,"symbol":"-F 2uv 2vw 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-330","+000+000-396","+000+000-936","+000+000-990","+000-000+303","+000-000+369","+000-000+909","+000-000+963","+000-000-033","+000-000-099","+000-000-639","+000-000-693","-000+000+033","-000+000+099","-000+000+639","-000+000+693","-000+000-303","-000+000-369","-000+000-909","-000+000-963","-000-000+330","-000-000+396","-000-000+936","-000-000+990","-000-000-000","-000-000-066","-000-000-606","-000-000-660","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00330","0+000+-00396","0+000+-00936","0+000+-00990","0+000-+00303","0+000-+00369","0+000-+00909","0+000-+00963","0+000--00033","0+000--00099","0+000--00639","0+000--00693","0-000++00033","0-000++00099","0-000++00639","0-000++00693","0-000+-00303","0-000+-00369","0-000+-00909","0-000+-00963","0-000-+00330","0-000-+00396","0-000-+00936","0-000-+00990","0-000--00000","0-000--00066","0-000--00606","0-000--00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0330","00++000-0396","00++000-0936","00++000-0990","00+-000+0303","00+-000+0369","00+-000+0909","00+-000+0963","00+-000-0033","00+-000-0099","00+-000-0639","00+-000-0693","00-+000+0033","00-+000+0099","00-+000+0639","00-+000+0693","00-+000-0303","00-+000-0369","00-+000-0909","00-+000-0963","00--000+0330","00--000+0396","00--000+0936","00--000+0990","00--000-0000","00--000-0066","00--000-0606","00--000-0660"]},{"hall":500,"number":204,"symbol":"-I 2 2 3","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+000","+000-000+666","+000-000-000","+000-000-666","-000+000+000","-000+000+666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","-000-000-000","-000-000-666","0+000++00000","0+000++00666","0+000+-00000","0+000+-00666","0+000-+00000","0+000-+00666","0+000--00000","0+000--00666","0-000++00000","0-000++00666","0-000+-00000","0-000+-00666","0-000-+00000","0-000-+00666","0-000--00000","0-000--00666","00++000+0000","00++000+0666","00++000-0000","00++000-0666","00+-000+0000","00+-000+0666","00+-000-0000","00+-000-0666","00-+000+0000","00-+000+0666","00-+000-0000","00-+000-0666","00--000+0000","00--000+0666","00--000-0000","00--000-0666"]},{"hall":501,"number":205,"symbol":"-P 2ac 2ab 3","operations":["+000+000+000","+000+000-606","+000-000+066","+000-000-660","-000+000+660","-000+000-066","-000-000+606","-000-000-000","0+000++00000","0+000+-00606","0+000-+00066","0+000--00660","0-000++00660","0-000+-00066","0-000-+00606","0-000--00000","00++000+0000","00++000-0606","00+-000+0066","00+-000-0660","00-+000+0660","00-+000-0066","00--000+0606","00--000-0000"]},{"hall":502,"number":206,"symbol":"-I 2b 2c 3","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","+000-000+066","+000-000+600","+000-000-006","+000-000-660","-000+000+006","-000+000+660","-000+000-066","-000+000-600","-000-000+060","-000-000+606","-000-000-000","-000-000-666","0+000++00000","0+000++00666","0+000+-00060","0+000+-00606","0+000-+00066","0+000-+00600","0+000--00006","0+000--00660","0-000++00006","0-000++00660","0-000+-00066","0-000+-00600","0-000-+00060","0-000-+00606","0-000--00000","0-000--00666","00++000+0000","00++000+0666","00++000-0060","00++000-0606","00+-000+0066","00+-000+0600","00+-000-0006","00+-000-0660","00-+000+0006","00-+000+0660","00-+000-0066","00-+000-0600","00--000+0060","00--000+0606","00--000-0000","00--000-0666"]},{"hall":503,"number":207,"symbol":"P 4 2 3","operations":["+000+000+000","+000-000-000","+0000+0-0000","+0000-0+0000","-000+000-000","-000-000+000","-0000+0+0000","-0000-0-0000","0+0+0000-000","0+0-0000+000","0+000++00000","0+000--00000","0-0+0000+000","0-0-0000-000","0-000+-00000","0-000-+00000","00++000+0000","00+-000-0000","00+0+0-00000","00+0-0+00000","00-+000-0000","00--000+0000","00-0+0+00000","00-0-0-00000"]},{"hall":504,"number":208,"symbol":"P 4n 2 3","operations":["+000+000+000","+000-000-000","+0000+0-0666","+0000-0+0666","-000+000-000","-000-000+000","-0000+0+0666","-0000-0-0666","0+0+0000-666","0+0-0000+666","0+000++00000","0+000--00000","0-0+0000+666","0-0-0000-666","0-000+-00000","0-000-+00000","00++000+0000","00+-000-0000","00+0+0-00666","00+0-0+00666","00-+000-0000","00--000+0000","00-0+0+00666","00-0-0-00666"]},{"hall":505,"number":209,"symbol":"F 4 2 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","+0000+0-0000","+0000+0-0066","+0000+0-0606","+0000+0-0660","+0000-0+0000","+0000-0+0066","+0000-0+0606","+0000-0+0660","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-0000+0+0000","-0000+0+0066","-0000+0+0606","-0000+0+0660","-0000-0-0000","-0000-0-0066","-0000-0-0606","-0000-0-0660","0+0+0000-000","0+0+0000-066","0+0+0000-606","0+0+0000-660","0+0-0000+000","0+0-0000+066","0+0-0000+606","0+0-0000+660","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-0+0000+000","0-0+0000+066","0-0+0000+606","0-0+0000+660","0-0-0000-000","0-0-0000-066","0-0-0000-606","0-0-0000-660","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00+0+0-00000","00+0+0-00066","00+0+0-00606","00+0+0-00660","00+0-0+00000","00+0-0+00066","00+0-0+00606","00+0-0+00660","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00-0+0+00000","00-0+0+00066","00-0+0+00606","00-0+0+00660","00-0-0-00000","00-0-0-00066","00-0-0-00606","00-0-0-00660"]},{"hall":506,"number":210,"symbol":"F 4d 2 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","+0000+0-0333","+0000+0-0399","+0000+0-0939","+0000+0-0993","+0000-0+0333","+0000-0+0399","+0000-0+0939","+0000-0+0993","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-0000+0+0333","-0000+0+0399","-0000+0+0939","-0000+0+0993","-0000-0-0333","-0000-0-0399","-0000-0-0939","-0000-0-0993","0+0+0000-333","0+0+0000-399","0+0+0000-939","0+0+0000-993","0+0-0000+333","0+0-0000+399","0+0-0000+939","0+0-0000+993","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-0+0000+333","0-0+0000+399","0-0+0000+939","0-0+0000+993","0-0-0000-333","0-0-0000-399","0-0-0000-939","0-0-0000-993","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00+0+0-00333","00+0+0-00399","00+0+0-00939","00+0+0-00993","00+0-0+00333","00+0-0+00399","00+0-0+00939","00+0-0+00993","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00-0+0+00333","00-0+0+00399","00-0+0+00939","00-0+0+00993","00-0-0-00333","00-0-0-00399","00-0-0-00939","00-0-0-00993"]},{"hall":507,"number":211,"symbol":"I 4 2 3","operations":["+000+000+000","+000+000+666","+000-000-000","+000-000-666","+0000+0-0000","+0000+0-0666","+0000-0+0000","+0000-0+0666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","-0000+0+0000","-0000+0+0666","-0000-0-0000","-0000-0-0666","0+0+0000-000","0+0+0000-666","0+0-0000+000","0+0-0000+666","0+000++00000","0+000++00666","0+000--00000","0+000--00666","0-0+0000+000","0-0+0000+666","0-0-0000-000","0-0-0000-666","0-000+-00000","0-000+-00666","0-000-+00000","0-000-+00666","00++000+0000","00++000+0666","00+-000-0000","00+-000-0666","00+0+0-00000","00+0+0-00666","00+0-0+00000","00+0-0+00666","00-+000-0000","00-+000-0666","00--000+0000","00--000+0666","00-0+0+00000","00-0+0+00666","00-0-0-00000","00-0-0-00666"]},{"hall":508,"number":212,"symbol":"P 4acd 2ab 3","operations":["+000+000+000","+000-000-660","+0000+0-0399","+0000-0+0993","-000+000-066","-000-000+606","-0000+0+0939","-0000-0-0333","0+0+0000-399","0+0-0000+993","0+000++00000","0+000--00660","0-0+0000+939","0-0-0000-333","0-000+-00066","0-000-+00606","00++000+0000","00+-000-0660","00+0+0-00399","00+0-0+00993","00-+000-0066","00--000+0606","00-0+0+00939","00-0-0-00333"]},{"hall":509,"number":213,"symbol":"P 4bd 2ab 3","operations":["+000+000+000","+000-000-660","+0000+0-0933","+0000-0+0339","-000+000-066","-000-000+606","-0000+0+0393","-0000-0-0999","0+0+0000-933","0+0-0000+339","0+000++00000","0+000--00660","0-0+0000+393","0-0-0000-999","0-000+-00066","0-000-+00606","00++000+0000","00+-000-0660","00+0+0-00933","00+0-0+00339","00-+000-0066","00--000+0606","00-0+0+00393","00-0-0-00999"]},{"hall":510,"number":214,"symbol":"I 4bd 2c 3","operations":["+000+000+000","+000+000+666","+000-000-006","+000-000-660","+0000+0-0399","+0000+0-0933","+0000-0+0339","+0000-0+0993","-000+000-066","-000+000-600","-000-000+060","-000-000+606","-0000+0+0393","-0000+0+0939","-0000-0-0333","-0000-0-0999","0+0+0000-399","0+0+0000-933","0+0-0000+339","0+0-0000+993","0+000++00000","0+000++00666","0+000--00006","0+000--00660","0-0+0000+393","0-0+0000+939","0-0-0000-333","0-0-0000-999","0-000+-00066","0-000+-00600","0-000-+00060","0-000-+00606","00++000+0000","00++000+0666","00+-000-0006","00+-000-0660","00+0+0-00399","00+0+0-00933","00+0-0+00339","00+0-0+00993","00-+000-0066","00-+000-0600","00--000+0060","00--000+0606","00-0+0+00393","00-0+0+00939","00-0-0-00333","00-0-0-00999"]},{"hall":511,"number":215,"symbol":"P -4 2 3","operations":["+000+000+000","+000-000-000","+0000+0+0000","+0000-0-0000","-000+000-000","-000-000+000","-0000+0-0000","-0000-0+0000","0+0+0000+000","0+0-0000-000","0+000++00000","0+000--00000","0-0+0000-000","0-0-0000+000","0-000+-00000","0-000-+00000","00++000+0000","00+-000-0000","00+0+0+00000","00+0-0-00000","00-+000-0000","00--000+0000","00-0+0-00000","00-0-0+00000"]},{"hall":512,"number":216,"symbol":"F -4 2 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","+0000+0+0000","+0000+0+0066","+0000+0+0606","+0000+0+0660","+0000-0-0000","+0000-0-0066","+0000-0-0606","+0000-0-0660","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-0000+0-0000","-0000+0-0066","-0000+0-0606","-0000+0-0660","-0000-0+0000","-0000-0+0066","-0000-0+0606","-0000-0+0660","0+0+0000+000","0+0+0000+066","0+0+0000+606","0+0+0000+660","0+0-0000-000","0+0-0000-066","0+0-0000-606","0+0-0000-660","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-0+0000-000","0-0+0000-066","0-0+0000-606","0-0+0000-660","0-0-0000+000","0-0-0000+066","0-0-0000+606","0-0-0000+660","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00+0+0+00000","00+0+0+00066","00+0+0+00606","00+0+0+00660","00+0-0-00000","00+0-0-00066","00+0-0-00606","00+0-0-00660","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00-0+0-00000","00-0+0-00066","00-0+0-00606","00-0+0-00660","00-0-0+00000","00-0-0+00066","00-0-0+00606","00-0-0+00660"]},{"hall":513,"number":217,"symbol":"I -4 2 3","operations":["+000+000+000","+000+000+666","+000-000-000","+000-000-666","+0000+0+0000","+0000+0+0666","+0000-0-0000","+0000-0-0666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","-0000+0-0000","-0000+0-0666","-0000-0+0000","-0000-0+0666","0+0+0000+000","0+0+0000+666","0+0-0000-000","0+0-0000-666","0+000++00000","0+000++00666","0+000--00000","0+000--00666","0-0+0000-000","0-0+0000-666","0-0-0000+000","0-0-0000+666","0-000+-00000","0-000+-00666","0-000-+00000","0-000-+00666","00++000+0000","00++000+0666","00+-000-0000","00+-000-0666","00+0+0+00000","00+0+0+00666","00+0-0-00000","00+0-0-00666","00-+000-0000","00-+000-0666","00--000+0000","00--000+0666","00-0+0-00000","00-0+0-00666","00-0-0+00000","00-0-0+00666"]},{"hall":514,"number":218,"symbol":"P -4n 2 3","operations":["+000+000+000","+000-000-000","+0000+0+0666","+0000-0-0666","-000+000-000","-000-000+000","-0000+0-0666","-0000-0+0666","0+0+0000+666","0+0-0000-666","0+000++00000","0+000--00000","0-0+0000-666","0-0-0000+666","0-000+-00000","0-000-+00000","00++000+0000","00+-000-0000","00+0+0+00666","00+0-0-00666","00-+000-0000","00--000+0000","00-0+0-00666","00-0-0+00666"]},{"hall":515,"number":219,"symbol":"F -4a 2 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","+0000+0+0006","+0000+0+0060","+0000+0+0600","+0000+0+0666","+0000-0-0006","+0000-0-0060","+0000-0-0600","+0000-0-0666","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-0000+0-0006","-0000+0-0060","-0000+0-0600","-0000+0-0666","-0000-0+0006","-0000-0+0060","-0000-0+0600","-0000-0+0666","0+0+0000+006","0+0+0000+060","0+0+0000+600","0+0+0000+666","0+0-0000-006","0+0-0000-060","0+0-0000-600","0+0-0000-666","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-0+0000-006","0-0+0000-060","0-0+0000-600","0-0+0000-666","0-0-0000+006","0-0-0000+060","0-0-0000+600","0-0-0000+666","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00+0+0+00006","00+0+0+00060","00+0+0+00600","00+0+0+00666","00+0-0-00006","00+0-0-00060","00+0-0-00600","00+0-0-00666","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00-0+0-00006","00-0+0-00060","00-0+0-00600","00-0+0-00666","00-0-0+00006","00-0-0+00060","00-0-0+00600","00-0-0+00666"]},{"hall":516,"number":220,"symbol":"I -4bd 2c 3","operations":["+000+000+000","+000+000+666","+000-000-006","+000-000-660","+0000+0+0333","+0000+0+0999","+0000-0-0393","+0000-0-0939","-000+000-066","-000+000-600","-000-000+060","-000-000+606","-0000+0-0339","-0000+0-0993","-0000-0+0399","-0000-0+0933","0+0+0000+333","0+0+0000+999","0+0-0000-393","0+0-0000-939","0+000++00000","0+000++00666","0+000--00006","0+000--00660","0-0+0000-339","0-0+0000-993","0-0-0000+399","0-0-0000+933","0-000+-00066","0-000+-00600","0-000-+00060","0-000-+00606","00++000+0000","00++000+0666","00+-000-0006","00+-000-0660","00+0+0+00333","00+0+0+00999","00+0-0-00393","00+0-0-00939","00-+000-0066","00-+000-0600","00--000+0060","00--000+0606","00-0+0-00339","00-0+0-00993","00-0-0+00399","00-0-0+00933"]},{"hall":517,"number":221,"symbol":"-P 4 2 3","operations":["+000+000+000","+000+000-000","+000-000+000","+000-000-000","+0000+0+0000","+0000+0-0000","+0000-0+0000","+0000-0-0000","-000+000+000","-000+000-000","-000-000+000","-000-000-000","-0000+0+0000","-0000+0-0000","-0000-0+0000","-0000-0-0000","0+0+0000+000","0+0+0000-000","0+0-0000+000","0+0-0000-000","0+000++00000","0+000+-00000","0+000-+00000","0+000--00000","0-0+0000+000","0-0+0000-000","0-0-0000+000","0-0-0000-000","0-000++00000","0-000+-00000","0-000-+00000","0-000--00000","00++000+0000","00++000-0000","00+-000+0000","00+-000-0000","00+0+0+00000","00+0+0-00000","00+0-0+00000","00+0-0-00000","00-+000+0000","00-+000-0000","00--000+0000","00--000-0000","00-0+0+00000","00-0+0-00000","00-0-0+00000","00-0-0-00000"]},{"hall":518,"number":222,"symbol":"P 4 2 3 -1n","operations":["+000+000+000","+000+000-666","+000-000+666","+000-000-000","+0000+0+0666","+0000+0-0000","+0000-0+0000","+0000-0-0666","-000+000+666","-000+000-000","-000-000+000","-000-000-666","-0000+0+0000","-0000+0-0666","-0000-0+0666","-0000-0-0000","0+0+0000+666","0+0+0000-000","0+0-0000+000","0+0-0000-666","0+000++00000","0+000+-00666","0+000-+00666","0+000--00000","0-0+0000+000","0-0+0000-666","0-0-0000+666","0-0-0000-000","0-000++00666","0-000+-00000","0-000-+00000","0-000--00666","00++000+0000","00++000-0666","00+-000+0666","00+-000-0000","00+0+0+00666","00+0+0-00000","00+0-0+00000","00+0-0-00666","00-+000+0666","00-+000-0000","00--000+0000","00--000-0666","00-0+0+00000","00-0+0-00666","00-0-0+00666","00-0-0-00000"]},{"hall":519,"number":222,"symbol":"-P 4a 2bc 3","operations":["+000+000+000","+000+000-660","+000-000+606","+000-000-066","+0000+0+0666","+0000+0-0006","+0000-0+0060","+0000-0-0600","-000+000+066","-000+000-606","-000-000+660","-000-000-000","-0000+0+0600","-0000+0-0060","-0000-0+0006","-0000-0-0666","0+0+0000+666","0+0+0000-006","0+0-0000+060","0+0-0000-600","0+000++00000","0+000+-00660","0+000-+00606","0+000--00066","0-0+0000+600","0-0+0000-060","0-0-0000+006","0-0-0000-666","0-000++00066","0-000+-00606","0-000-+00660","0-000--00000","00++000+0000","00++000-0660","00+-000+0606","00+-000-0066","00+0+0+00666","00+0+0-00006","00+0-0+00060","00+0-0-00600","00-+000+0066","00-+000-0606","00--000+0660","00--000-0000","00-0+0+00600","00-0+0-00060","00-0-0+00006","00-0-0-00666"]},{"hall":520,"number":223,"symbol":"-P 4n 2 3","operations":["+000+000+000","+000+000-000","+000-000+000","+000-000-000","+0000+0+0666","+0000+0-0666","+0000-0+0666","+0000-0-0666","-000+000+000","-000+000-000","-000-000+000","-000-000-000","-0000+0+0666","-0000+0-0666","-0000-0+0666","-0000-0-0666","0+0+0000+666","0+0+0000-666","0+0-0000+666","0+0-0000-666","0+000++00000","0+000+-00000","0+000-+00000","0+000--00000","0-0+0000+666","0-0+0000-666","0-0-0000+666","0-0-0000-666","0-000++00000","0-000+-00000","0-000-+00000","0-000--00000","00++000+0000","00++000-0000","00+-000+0000","00+-000-0000","00+0+0+00666","00+0+0-00666","00+0-0+00666","00+0-0-00666","00-+000+0000","00-+000-0000","00--000+0000","00--000-0000","00-0+0+00666","00-0+0-00666","00-0-0+00666","00-0-0-00666"]},{"hall":521,"number":224,"symbol":"P 4n 2 3 -1n","operations":["+000+000+000","+000+000-666","+000-000+666","+000-000-000","+0000+0+0000","+0000+0-0666","+0000-0+0666","+0000-0-0000","-000+000+666","-000+000-000","-000-000+000","-000-000-666","-0000+0+0666","-0000+0-0000","-0000-0+0000","-0000-0-0666","0+0+0000+000","0+0+0000-666","0+0-0000+666","0+0-0000-000","0+000++00000","0+000+-00666","0+000-+00666","0+000--00000","0-0+0000+666","0-0+0000-000","0-0-0000+000","0-0-0000-666","0-000++00666","0-000+-00000","0-000-+00000","0-000--00666","00++000+0000","00++000-0666","00+-000+0666","00+-000-0000","00+0+0+00000","00+0+0-00666","00+0-0+00666","00+0-0-00000","00-+000+0666","00-+000-0000","00--000+0000","00--000-0666","00-0+0+00666","00-0+0-00000","00-0-0+00000","00-0-0-00666"]},{"hall":522,"number":224,"symbol":"-P 4bc 2bc 3","operations":["+000+000+000","+000+000-660","+000-000+606","+000-000-066","+0000+0+0000","+0000+0-0660","+0000-0+0606","+0000-0-0066","-000+000+066","-000+000-606","-000-000+660","-000-000-000","-0000+0+0066","-0000+0-0606","-0000-0+0660","-0000-0-0000","0+0+0000+000","0+0+0000-660","0+0-0000+606","0+0-0000-066","0+000++00000","0+000+-00660","0+000-+00606","0+000--00066","0-0+0000+066","0-0+0000-606","0-0-0000+660","0-0-0000-000","0-000++00066","0-000+-00606","0-000-+00660","0-000--00000","00++000+0000","00++000-0660","00+-000+0606","00+-000-0066","00+0+0+00000","00+0+0-00660","00+0-0+00606","00+0-0-00066","00-+000+0066","00-+000-0606","00--000+0660","00--000-0000","00-0+0+00066","00-0+0-00606","00-0-0+00660","00-0-0-00000"]},{"hall":523,"number":225,"symbol":"-F 4 2 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-000","+000+000-066","+000+000-606","+000+000-660","+000-000+000","+000-000+066","+000-000+606","+000-000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","+0000+0+0000","+0000+0+0066","+0000+0+0606","+0000+0+0660","+0000+0-0000","+0000+0-0066","+0000+0-0606","+0000+0-0660","+0000-0+0000","+0000-0+0066","+0000-0+0606","+0000-0+0660","+0000-0-0000","+0000-0-0066","+0000-0-0606","+0000-0-0660","-000+000+000","-000+000+066","-000+000+606","-000+000+660","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-000-000-000","-000-000-066","-000-000-606","-000-000-660","-0000+0+0000","-0000+0+0066","-0000+0+0606","-0000+0+0660","-0000+0-0000","-0000+0-0066","-0000+0-0606","-0000+0-0660","-0000-0+0000","-0000-0+0066","-0000-0+0606","-0000-0+0660","-0000-0-0000","-0000-0-0066","-0000-0-0606","-0000-0-0660","0+0+0000+000","0+0+0000+066","0+0+0000+606","0+0+0000+660","0+0+0000-000","0+0+0000-066","0+0+0000-606","0+0+0000-660","0+0-0000+000","0+0-0000+066","0+0-0000+606","0+0-0000+660","0+0-0000-000","0+0-0000-066","0+0-0000-606","0+0-0000-660","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00000","0+000+-00066","0+000+-00606","0+000+-00660","0+000-+00000","0+000-+00066","0+000-+00606","0+000-+00660","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-0+0000+000","0-0+0000+066","0-0+0000+606","0-0+0000+660","0-0+0000-000","0-0+0000-066","0-0+0000-606","0-0+0000-660","0-0-0000+000","0-0-0000+066","0-0-0000+606","0-0-0000+660","0-0-0000-000","0-0-0000-066","0-0-0000-606","0-0-0000-660","0-000++00000","0-000++00066","0-000++00606","0-000++00660","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","0-000--00000","0-000--00066","0-000--00606","0-000--00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0000","00++000-0066","00++000-0606","00++000-0660","00+-000+0000","00+-000+0066","00+-000+0606","00+-000+0660","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00+0+0+00000","00+0+0+00066","00+0+0+00606","00+0+0+00660","00+0+0-00000","00+0+0-00066","00+0+0-00606","00+0+0-00660","00+0-0+00000","00+0-0+00066","00+0-0+00606","00+0-0+00660","00+0-0-00000","00+0-0-00066","00+0-0-00606","00+0-0-00660","00-+000+0000","00-+000+0066","00-+000+0606","00-+000+0660","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00--000-0000","00--000-0066","00--000-0606","00--000-0660","00-0+0+00000","00-0+0+00066","00-0+0+00606","00-0+0+00660","00-0+0-00000","00-0+0-00066","00-0+0-00606","00-0+0-00660","00-0-0+00000","00-0-0+00066","00-0-0+00606","00-0-0+00660","00-0-0-00000","00-0-0-00066","00-0-0-00606","00-0-0-00660"]},{"hall":524,"number":226,"symbol":"-F 4a 2 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-000","+000+000-066","+000+000-606","+000+000-660","+000-000+000","+000-000+066","+000-000+606","+000-000+660","+000-000-000","+000-000-066","+000-000-606","+000-000-660","+0000+0+0006","+0000+0+0060","+0000+0+0600","+0000+0+0666","+0000+0-0006","+0000+0-0060","+0000+0-0600","+0000+0-0666","+0000-0+0006","+0000-0+0060","+0000-0+0600","+0000-0+0666","+0000-0-0006","+0000-0-0060","+0000-0-0600","+0000-0-0666","-000+000+000","-000+000+066","-000+000+606","-000+000+660","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-000-000-000","-000-000-066","-000-000-606","-000-000-660","-0000+0+0006","-0000+0+0060","-0000+0+0600","-0000+0+0666","-0000+0-0006","-0000+0-0060","-0000+0-0600","-0000+0-0666","-0000-0+0006","-0000-0+0060","-0000-0+0600","-0000-0+0666","-0000-0-0006","-0000-0-0060","-0000-0-0600","-0000-0-0666","0+0+0000+006","0+0+0000+060","0+0+0000+600","0+0+0000+666","0+0+0000-006","0+0+0000-060","0+0+0000-600","0+0+0000-666","0+0-0000+006","0+0-0000+060","0+0-0000+600","0+0-0000+666","0+0-0000-006","0+0-0000-060","0+0-0000-600","0+0-0000-666","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00000","0+000+-00066","0+000+-00606","0+000+-00660","0+000-+00000","0+000-+00066","0+000-+00606","0+000-+00660","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-0+0000+006","0-0+0000+060","0-0+0000+600","0-0+0000+666","0-0+0000-006","0-0+0000-060","0-0+0000-600","0-0+0000-666","0-0-0000+006","0-0-0000+060","0-0-0000+600","0-0-0000+666","0-0-0000-006","0-0-0000-060","0-0-0000-600","0-0-0000-666","0-000++00000","0-000++00066","0-000++00606","0-000++00660","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","0-000--00000","0-000--00066","0-000--00606","0-000--00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0000","00++000-0066","00++000-0606","00++000-0660","00+-000+0000","00+-000+0066","00+-000+0606","00+-000+0660","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00+0+0+00006","00+0+0+00060","00+0+0+00600","00+0+0+00666","00+0+0-00006","00+0+0-00060","00+0+0-00600","00+0+0-00666","00+0-0+00006","00+0-0+00060","00+0-0+00600","00+0-0+00666","00+0-0-00006","00+0-0-00060","00+0-0-00600","00+0-0-00666","00-+000+0000","00-+000+0066","00-+000+0606","00-+000+0660","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00--000-0000","00--000-0066","00--000-0606","00--000-0660","00-0+0+00006","00-0+0+00060","00-0+0+00600","00-0+0+00666","00-0+0-00006","00-0+0-00060","00-0+0-00600","00-0+0-00666","00-0-0+00006","00-0-0+00060","00-0-0+00600","00-0-0+00666","00-0-0-00006","00-0-0-00060","00-0-0-00600","00-0-0-00666"]},{"hall":525,"number":227,"symbol":"F 4d 2 3 -1d","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-333","+000+000-399","+000+000-939","+000+000-993","+000-000+333","+000-000+399","+000-000+939","+000-000+993","+000-000-000","+000-000-066","+000-000-606","+000-000-660","+0000+0+0000","+0000+0+0066","+0000+0+0606","+0000+0+0660","+0000+0-0333","+0000+0-0399","+0000+0-0939","+0000+0-0993","+0000-0+0333","+0000-0+0399","+0000-0+0939","+0000-0+0993","+0000-0-0000","+0000-0-0066","+0000-0-0606","+0000-0-0660","-000+000+333","-000+000+399","-000+000+939","-000+000+993","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-000-000-333","-000-000-399","-000-000-939","-000-000-993","-0000+0+0333","-0000+0+0399","-0000+0+0939","-0000+0+0993","-0000+0-0000","-0000+0-0066","-0000+0-0606","-0000+0-0660","-0000-0+0000","-0000-0+0066","-0000-0+0606","-0000-0+0660","-0000-0-0333","-0000-0-0399","-0000-0-0939","-0000-0-0993","0+0+0000+000","0+0+0000+066","0+0+0000+606","0+0+0000+660","0+0+0000-333","0+0+0000-399","0+0+0000-939","0+0+0000-993","0+0-0000+333","0+0-0000+399","0+0-0000+939","0+0-0000+993","0+0-0000-000","0+0-0000-066","0+0-0000-606","0+0-0000-660","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00333","0+000+-00399","0+000+-00939","0+000+-00993","0+000-+00333","0+000-+00399","0+000-+00939","0+000-+00993","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-0+0000+333","0-0+0000+399","0-0+0000+939","0-0+0000+993","0-0+0000-000","0-0+0000-066","0-0+0000-606","0-0+0000-660","0-0-0000+000","0-0-0000+066","0-0-0000+606","0-0-0000+660","0-0-0000-333","0-0-0000-399","0-0-0000-939","0-0-0000-993","0-000++00333","0-000++00399","0-000++00939","0-000++00993","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","0-000--00333","0-000--00399","0-000--00939","0-000--00993","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0333","00++000-0399","00++000-0939","00++000-0993","00+-000+0333","00+-000+0399","00+-000+0939","00+-000+0993","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00+0+0+00000","00+0+0+00066","00+0+0+00606","00+0+0+00660","00+0+0-00333","00+0+0-00399","00+0+0-00939","00+0+0-00993","00+0-0+00333","00+0-0+00399","00+0-0+00939","00+0-0+00993","00+0-0-00000","00+0-0-00066","00+0-0-00606","00+0-0-00660","00-+000+0333","00-+000+0399","00-+000+0939","00-+000+0993","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00--000-0333","00--000-0399","00--000-0939","00--000-0993","00-0+0+00333","00-0+0+00399","00-0+0+00939","00-0+0+00993","00-0+0-00000","00-0+0-00066","00-0+0-00606","00-0+0-00660","00-0-0+00000","00-0-0+00066","00-0-0+00606","00-0-0+00660","00-0-0-00333","00-0-0-00399","00-0-0-00939","00-0-0-00993"]},{"hall":526,"number":227,"symbol":"-F 4vw 2vw 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-330","+000+000-396","+000+000-936","+000+000-990","+000-000+303","+000-000+369","+000-000+909","+000-000+963","+000-000-033","+000-000-099","+000-000-639","+000-000-693","+0000+0+0000","+0000+0+0066","+0000+0+0606","+0000+0+0660","+0000+0-0330","+0000+0-0396","+0000+0-0936","+0000+0-0990","+0000-0+0303","+0000-0+0369","+0000-0+0909","+0000-0+0963","+0000-0-0033","+0000-0-0099","+0000-0-0639","+0000-0-0693","-000+000+033","-000+000+099","-000+000+639","-000+000+693","-000+000-303","-000+000-369","-000+000-909","-000+000-963","-000-000+330","-000-000+396","-000-000+936","-000-000+990","-000-000-000","-000-000-066","-000-000-606","-000-000-660","-0000+0+0033","-0000+0+0099","-0000+0+0639","-0000+0+0693","-0000+0-0303","-0000+0-0369","-0000+0-0909","-0000+0-0963","-0000-0+0330","-0000-0+0396","-0000-0+0936","-0000-0+0990","-0000-0-0000","-0000-0-0066","-0000-0-0606","-0000-0-0660","0+0+0000+000","0+0+0000+066","0+0+0000+606","0+0+0000+660","0+0+0000-330","0+0+0000-396","0+0+0000-936","0+0+0000-990","0+0-0000+303","0+0-0000+369","0+0-0000+909","0+0-0000+963","0+0-0000-033","0+0-0000-099","0+0-0000-639","0+0-0000-693","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00330","0+000+-00396","0+000+-00936","0+000+-00990","0+000-+00303","0+000-+00369","0+000-+00909","0+000-+00963","0+000--00033","0+000--00099","0+000--00639","0+000--00693","0-0+0000+033","0-0+0000+099","0-0+0000+639","0-0+0000+693","0-0+0000-303","0-0+0000-369","0-0+0000-909","0-0+0000-963","0-0-0000+330","0-0-0000+396","0-0-0000+936","0-0-0000+990","0-0-0000-000","0-0-0000-066","0-0-0000-606","0-0-0000-660","0-000++00033","0-000++00099","0-000++00639","0-000++00693","0-000+-00303","0-000+-00369","0-000+-00909","0-000+-00963","0-000-+00330","0-000-+00396","0-000-+00936","0-000-+00990","0-000--00000","0-000--00066","0-000--00606","0-000--00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0330","00++000-0396","00++000-0936","00++000-0990","00+-000+0303","00+-000+0369","00+-000+0909","00+-000+0963","00+-000-0033","00+-000-0099","00+-000-0639","00+-000-0693","00+0+0+00000","00+0+0+00066","00+0+0+00606","00+0+0+00660","00+0+0-00330","00+0+0-00396","00+0+0-00936","00+0+0-00990","00+0-0+00303","00+0-0+00369","00+0-0+00909","00+0-0+00963","00+0-0-00033","00+0-0-00099","00+0-0-00639","00+0-0-00693","00-+000+0033","00-+000+0099","00-+000+0639","00-+000+0693","00-+000-0303","00-+000-0369","00-+000-0909","00-+000-0963","00--000+0330","00--000+0396","00--000+0936","00--000+0990","00--000-0000","00--000-0066","00--000-0606","00--000-0660","00-0+0+00033","00-0+0+00099","00-0+0+00639","00-0+0+00693","00-0+0-00303","00-0+0-00369","00-0+0-00909","00-0+0-00963","00-0-0+00330","00-0-0+00396","00-0-0+00936","00-0-0+00990","00-0-0-00000","00-0-0-00066","00-0-0-00606","00-0-0-00660"]},{"hall":527,"number":228,"symbol":"F 4d 2 3 -1ad","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-339","+000+000-393","+000+000-933","+000+000-999","+000-000+339","+000-000+393","+000-000+933","+000-000+999","+000-000-000","+000-000-066","+000-000-606","+000-000-660","+0000+0+0006","+0000+0+0060","+0000+0+0600","+0000+0+0666","+0000+0-0333","+0000+0-0399","+0000+0-0939","+0000+0-0993","+0000-0+0333","+0000-0+0399","+0000-0+0939","+0000-0+0993","+0000-0-0006","+0000-0-0060","+0000-0-0600","+0000-0-0666","-000+000+339","-000+000+393","-000+000+933","-000+000+999","-000+000-000","-000+000-066","-000+000-606","-000+000-660","-000-000+000","-000-000+066","-000-000+606","-000-000+660","-000-000-339","-000-000-393","-000-000-933","-000-000-999","-0000+0+0333","-0000+0+0399","-0000+0+0939","-0000+0+0993","-0000+0-0006","-0000+0-0060","-0000+0-0600","-0000+0-0666","-0000-0+0006","-0000-0+0060","-0000-0+0600","-0000-0+0666","-0000-0-0333","-0000-0-0399","-0000-0-0939","-0000-0-0993","0+0+0000+006","0+0+0000+060","0+0+0000+600","0+0+0000+666","0+0+0000-333","0+0+0000-399","0+0+0000-939","0+0+0000-993","0+0-0000+333","0+0-0000+399","0+0-0000+939","0+0-0000+993","0+0-0000-006","0+0-0000-060","0+0-0000-600","0+0-0000-666","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00339","0+000+-00393","0+000+-00933","0+000+-00999","0+000-+00339","0+000-+00393","0+000-+00933","0+000-+00999","0+000--00000","0+000--00066","0+000--00606","0+000--00660","0-0+0000+333","0-0+0000+399","0-0+0000+939","0-0+0000+993","0-0+0000-006","0-0+0000-060","0-0+0000-600","0-0+0000-666","0-0-0000+006","0-0-0000+060","0-0-0000+600","0-0-0000+666","0-0-0000-333","0-0-0000-399","0-0-0000-939","0-0-0000-993","0-000++00339","0-000++00393","0-000++00933","0-000++00999","0-000+-00000","0-000+-00066","0-000+-00606","0-000+-00660","0-000-+00000","0-000-+00066","0-000-+00606","0-000-+00660","0-000--00339","0-000--00393","0-000--00933","0-000--00999","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0339","00++000-0393","00++000-0933","00++000-0999","00+-000+0339","00+-000+0393","00+-000+0933","00+-000+0999","00+-000-0000","00+-000-0066","00+-000-0606","00+-000-0660","00+0+0+00006","00+0+0+00060","00+0+0+00600","00+0+0+00666","00+0+0-00333","00+0+0-00399","00+0+0-00939","00+0+0-00993","00+0-0+00333","00+0-0+00399","00+0-0+00939","00+0-0+00993","00+0-0-00006","00+0-0-00060","00+0-0-00600","00+0-0-00666","00-+000+0339","00-+000+0393","00-+000+0933","00-+000+0999","00-+000-0000","00-+000-0066","00-+000-0606","00-+000-0660","00--000+0000","00--000+0066","00--000+0606","00--000+0660","00--000-0339","00--000-0393","00--000-0933","00--000-0999","00-0+0+00333","00-0+0+00399","00-0+0+00939","00-0+0+00993","00-0+0-00006","00-0+0-00060","00-0+0-00600","00-0+0-00666","00-0-0+00006","00-0-0+00060","00-0-0+00600","00-0-0+00666","00-0-0-00333","00-0-0-00399","00-0-0-00939","00-0-0-00993"]},{"hall":528,"number":228,"symbol":"-F 4ud 2vw 3","operations":["+000+000+000","+000+000+066","+000+000+606","+000+000+660","+000+000-330","+000+000-396","+000+000-936","+000+000-990","+000-000+303","+000-000+369","+000-000+909","+000-000+963","+000-000-033","+000-000-099","+000-000-639","+000-000-693","+0000+0+0006","+0000+0+0060","+0000+0+0600","+0000+0+0666","+0000+0-0336","+0000+0-0390","+0000+0-0930","+0000+0-0996","+0000-0+0309","+0000-0+0363","+0000-0+0903","+0000-0+0969","+0000-0-0039","+0000-0-0093","+0000-0-0633","+0000-0-0699","-000+000+033","-000+000+099","-000+000+639","-000+000+693","-000+000-303","-000+000-369","-000+000-909","-000+000-963","-000-000+330","-000-000+396","-000-000+936","-000-000+990","-000-000-000","-000-000-066","-000-000-606","-000-000-660","-0000+0+0039","-0000+0+0093","-0000+0+0633","-0000+0+0699","-0000+0-0309","-0000+0-0363","-0000+0-0903","-0000+0-0969","-0000-0+0336","-0000-0+0390","-0000-0+0930","-0000-0+0996","-0000-0-0006","-0000-0-0060","-0000-0-0600","-0000-0-0666","0+0+0000+006","0+0+0000+060","0+0+0000+600","0+0+0000+666","0+0+0000-336","0+0+0000-390","0+0+0000-930","0+0+0000-996","0+0-0000+309","0+0-0000+363","0+0-0000+903","0+0-0000+969","0+0-0000-039","0+0-0000-093","0+0-0000-633","0+0-0000-699","0+000++00000","0+000++00066","0+000++00606","0+000++00660","0+000+-00330","0+000+-00396","0+000+-00936","0+000+-00990","0+000-+00303","0+000-+00369","0+000-+00909","0+000-+00963","0+000--00033","0+000--00099","0+000--00639","0+000--00693","0-0+0000+039","0-0+0000+093","0-0+0000+633","0-0+0000+699","0-0+0000-309","0-0+0000-363","0-0+0000-903","0-0+0000-969","0-0-0000+336","0-0-0000+390","0-0-0000+930","0-0-0000+996","0-0-0000-006","0-0-0000-060","0-0-0000-600","0-0-0000-666","0-000++00033","0-000++00099","0-000++00639","0-000++00693","0-000+-00303","0-000+-00369","0-000+-00909","0-000+-00963","0-000-+00330","0-000-+00396","0-000-+00936","0-000-+00990","0-000--00000","0-000--00066","0-000--00606","0-000--00660","00++000+0000","00++000+0066","00++000+0606","00++000+0660","00++000-0330","00++000-0396","00++000-0936","00++000-0990","00+-000+0303","00+-000+0369","00+-000+0909","00+-000+0963","00+-000-0033","00+-000-0099","00+-000-0639","00+-000-0693","00+0+0+00006","00+0+0+00060","00+0+0+00600","00+0+0+00666","00+0+0-00336","00+0+0-00390","00+0+0-00930","00+0+0-00996","00+0-0+00309","00+0-0+00363","00+0-0+00903","00+0-0+00969","00+0-0-00039","00+0-0-00093","00+0-0-00633","00+0-0-00699","00-+000+0033","00-+000+0099","00-+000+0639","00-+000+0693","00-+000-0303","00-+000-0369","00-+000-0909","00-+000-0963","00--000+0330","00--000+0396","00--000+0936","00--000+0990","00--000-0000","00--000-0066","00--000-0606","00--000-0660","00-0+0+00039","00-0+0+00093","00-0+0+00633","00-0+0+00699","00-0+0-00309","00-0+0-00363","00-0+0-00903","00-0+0-00969","00-0-0+00336","00-0-0+00390","00-0-0+00930","00-0-0+00996","00-0-0-00006","00-0-0-00060","00-0-0-00600","00-0-0-00666"]},{"hall":529,"number":229,"symbol":"-I 4 2 3","operations":["+000+000+000","+000+000+666","+000+000-000","+000+000-666","+000-000+000","+000-000+666","+000-000-000","+000-000-666","+0000+0+0000","+0000+0+0666","+0000+0-0000","+0000+0-0666","+0000-0+0000","+0000-0+0666","+0000-0-0000","+0000-0-0666","-000+000+000","-000+000+666","-000+000-000","-000+000-666","-000-000+000","-000-000+666","-000-000-000","-000-000-666","-0000+0+0000","-0000+0+0666","-0000+0-0000","-0000+0-0666","-0000-0+0000","-0000-0+0666","-0000-0-0000","-0000-0-0666","0+0+0000+000","0+0+0000+666","0+0+0000-000","0+0+0000-666","0+0-0000+000","0+0-0000+666","0+0-0000-000","0+0-0000-666","0+000++00000","0+000++00666","0+000+-00000","0+000+-00666","0+000-+00000","0+000-+00666","0+000--00000","0+000--00666","0-0+0000+000","0-0+0000+666","0-0+0000-000","0-0+0000-666","0-0-0000+000","0-0-0000+666","0-0-0000-000","0-0-0000-666","0-000++00000","0-000++00666","0-000+-00000","0-000+-00666","0-000-+00000","0-000-+00666","0-000--00000","0-000--00666","00++000+0000","00++000+0666","00++000-0000","00++000-0666","00+-000+0000","00+-000+0666","00+-000-0000","00+-000-0666","00+0+0+00000","00+0+0+00666","00+0+0-00000","00+0+0-00666","00+0-0+00000","00+0-0+00666","00+0-0-00000","00+0-0-00666","00-+000+0000","00-+000+0666","00-+000-0000","00-+000-0666","00--000+0000","00--000+0666","00--000-0000","00--000-0666","00-0+0+00000","00-0+0+00666","00-0+0-00000","00-0+0-00666","00-0-0+00000","00-0-0+00666","00-0-0-00000","00-0-0-00666"]},{"hall":530,"number":230,"symbol":"-I 4bd 2c 3","operations":["+000+000+000","+000+000+666","+000+000-060","+000+000-606","+000-000+066","+000-000+600","+000-000-006","+000-000-660","+0000+0+0333","+0000+0+0999","+0000+0-0399","+0000+0-0933","+0000-0+0339","+0000-0+0993","+0000-0-0393","+0000-0-0939","-000+000+006","-000+000+660","-000+000-066","-000+000-600","-000-000+060","-000-000+606","-000-000-000","-000-000-666","-0000+0+0393","-0000+0+0939","-0000+0-0339","-0000+0-0993","-0000-0+0399","-0000-0+0933","-0000-0-0333","-0000-0-0999","0+0+0000+333","0+0+0000+999","0+0+0000-399","0+0+0000-933","0+0-0000+339","0+0-0000+993","0+0-0000-393","0+0-0000-939","0+000++00000","0+000++00666","0+000+-00060","0+000+-00606","0+000-+00066","0+000-+00600","0+000--00006","0+000--00660","0-0+0000+393","0-0+0000+939","0-0+0000-339","0-0+0000-993","0-0-0000+399","0-0-0000+933","0-0-0000-333","0-0-0000-999","0-000++00006","0-000++00660","0-000+-00066","0-000+-00600","0-000-+00060","0-000-+00606","0-000--00000","0-000--00666","00++000+0000","00++000+0666","00++000-0060","00++000-0606","00+-000+0066","00+-000+0600","00+-000-0006","00+-000-0660","00+0+0+00333","00+0+0+00999","00+0+0-00399","00+0+0-00933","00+0-0+00339","00+0-0+00993","00+0-0-00393","00+0-0-00939","00-+000+0006","00-+000+0660","00-+000-0066","00-+000-0600","00--000+0060","00--000+0606","00--000-0000","00--000-0666","00-0+0+00393","00-0+0+00939","00-0+0-00339","00-0+0-00993","00-0-0+00399","00-0-0+00933","00-0-0-00333","00-0-0-00999"]}],"cifs":[{"name":"rock salt, Hall only, no loop","text":"data_t\n_space_group_name_Hall '-F 4 2 3'\n_cell_length_a 5.64\n_cell_length_b 5.64\n_cell_length_c 5.64\n_cell_angle_alpha 90\n_cell_angle_beta 90\n_cell_angle_gamma 90\nloop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\nNa1 Na 0 0 0\nCl2 Cl 0.5 0.5 0.5\n","hall":"-F 4 2 3","truthAtoms":8,"pymatgenAtoms":2,"pymatgenWarnings":["No _symmetry_equiv_pos_as_xyz type key found. Defaulting to P1."],"listed":null,"groupOrder":192},{"name":"rock salt, legacy Hall tag, no loop","text":"data_t\n_symmetry_space_group_name_Hall '-F 4 2 3'\n_cell_length_a 5.64\n_cell_length_b 5.64\n_cell_length_c 5.64\n_cell_angle_alpha 90\n_cell_angle_beta 90\n_cell_angle_gamma 90\nloop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\nNa1 Na 0 0 0\nCl2 Cl 0.5 0.5 0.5\n","hall":"-F 4 2 3","truthAtoms":8,"pymatgenAtoms":2,"pymatgenWarnings":["No _symmetry_equiv_pos_as_xyz type key found. Defaulting to P1."],"listed":null,"groupOrder":192},{"name":"P 21 general site, Hall only, no loop","text":"data_t\n_space_group_name_Hall 'P 2yb'\n_cell_length_a 5\n_cell_length_b 6\n_cell_length_c 7\n_cell_angle_alpha 90\n_cell_angle_beta 100\n_cell_angle_gamma 90\nloop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\nSi1 Si 0.12 0.23 0.34\n","hall":"P 2yb","truthAtoms":2,"pymatgenAtoms":1,"pymatgenWarnings":["No _symmetry_equiv_pos_as_xyz type key found. Defaulting to P1."],"listed":null,"groupOrder":2},{"name":"P 31 2 1 with origin shift, Hall only, no loop","text":"data_t\n_space_group_name_Hall 'P 31 2 (0 0 4)'\n_cell_length_a 4.9\n_cell_length_b 4.9\n_cell_length_c 5.4\n_cell_angle_alpha 90\n_cell_angle_beta 90\n_cell_angle_gamma 120\nloop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\nSi1 Si 0.47 0.0 0.0\nO2 O 0.41 0.27 0.12\n","hall":"P 31 2 (0 0 4)","truthAtoms":12,"pymatgenAtoms":2,"pymatgenWarnings":["No _symmetry_equiv_pos_as_xyz type key found. Defaulting to P1."],"listed":null,"groupOrder":6},{"name":"rhombohedral axes, Hall only, no loop","text":"data_t\n_space_group_name_Hall '-P 3* 2'\n_cell_length_a 5.1\n_cell_length_b 5.1\n_cell_length_c 5.1\n_cell_angle_alpha 55\n_cell_angle_beta 55\n_cell_angle_gamma 55\nloop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\nAl1 Al 0.35 0.35 0.35\nO2 O 0.55 0.95 0.25\n","hall":"-P 3* 2","truthAtoms":14,"pymatgenAtoms":2,"pymatgenWarnings":["No _symmetry_equiv_pos_as_xyz type key found. Defaulting to P1."],"listed":null,"groupOrder":12},{"name":"rock salt, Hall only, 48 point operations","text":"data_t\n_space_group_name_Hall '-F 4 2 3'\n_cell_length_a 5.64\n_cell_length_b 5.64\n_cell_length_c 5.64\n_cell_angle_alpha 90\n_cell_angle_beta 90\n_cell_angle_gamma 90\nloop_\n_symmetry_equiv_pos_as_xyz\n'x,y,z'\n'-x,-y,-z'\n'-y,x,z'\n'y,-x,-z'\n'-x,-y,z'\n'x,y,-z'\n'y,-x,z'\n'-y,x,-z'\n'x,-y,-z'\n'-x,y,z'\n'-y,-x,-z'\n'y,x,z'\n'-x,y,-z'\n'x,-y,z'\n'y,x,-z'\n'-y,-x,z'\n'z,x,y'\n'-z,-x,-y'\n'z,-y,x'\n'-z,y,-x'\n'z,-x,-y'\n'-z,x,y'\n'z,y,-x'\n'-z,-y,x'\n'-z,x,-y'\n'z,-x,y'\n'-z,-y,-x'\n'z,y,x'\n'-z,-x,y'\n'z,x,-y'\n'-z,y,x'\n'z,-y,-x'\n'y,z,x'\n'-y,-z,-x'\n'x,z,-y'\n'-x,-z,y'\n'-y,z,-x'\n'y,-z,x'\n'-x,z,y'\n'x,-z,-y'\n'-y,-z,x'\n'y,z,-x'\n'-x,-z,-y'\n'x,z,y'\n'y,-z,-x'\n'-y,z,x'\n'x,-z,y'\n'-x,z,-y'\nloop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\nNa1 Na 0 0 0\nCl2 Cl 0.5 0.5 0.5\n","hall":"-F 4 2 3","truthAtoms":8,"pymatgenAtoms":2,"pymatgenWarnings":[],"listed":48,"groupOrder":192}]} \ No newline at end of file diff --git a/Tests/DiffractoCoreTests/HallSymbolTests.swift b/Tests/DiffractoCoreTests/HallSymbolTests.swift new file mode 100644 index 0000000..c192ab8 --- /dev/null +++ b/Tests/DiffractoCoreTests/HallSymbolTests.swift @@ -0,0 +1,122 @@ +// +// HallSymbolTests.swift +// The Hall-symbol reader against spglib 2.8.0's 530 settings, exact, and the CIF that names its group by Hall symbol +// alone. Pins: tools/pins/cif-symmetry/hall-pins.py. +// + +import DiffractoKitTestSupport +import Foundation +import Testing +import DiffractoCore + +struct HallSymbolTests { + struct Pins: Decodable { + struct Group: Decodable { let hall: Int; let number: Int; let symbol: String; let operations: [String] } + struct PlantedCIF: Decodable { + let name: String; let text: String; let hall: String + let truthAtoms: Int; let pymatgenAtoms: Int; let listed: Int?; let groupOrder: Int + } + let spglib: String + let groups: [Group] + let cifs: [PlantedCIF] + } + + static func pins() throws -> Pins { + try JSONDecoder().decode(Pins.self, from: Data(contentsOf: Fixtures.directory.appendingPathComponent("hall-symbol-pins.json"))) + } + + /// The fixture's encoding: the rotation row by row as - 0 +, the translation in twelfths as three hex digits. + static func encode(_ op: SymmetryOperation) -> String { + var s = "" + for row in op.rotation.rows { for v in [row.x, row.y, row.z] { s.append(v < 0 ? "-" : v > 0 ? "+" : "0") } } + for t in [op.translation.x, op.translation.y, op.translation.z] { + let twelfths = Int((t * 12).rounded()) + s.append(Character(String(((twelfths % 12) + 12) % 12, radix: 16))) + } + return s + } + + /// Every one of the 530 Hall settings spglib lists reads to exactly spglib's operation set: same count, same + /// rotations, same translations in twelfths, centring included. No tolerance (readers are tested exact). + @Test func everySpglibHallSymbolReadsToItsOperations() throws { + let pins = try Self.pins() + #expect(pins.spglib == "2.8.0") + #expect(pins.groups.count == 530) + var failures: [String] = [] + for group in pins.groups { + do { + let ops = try HallSymbol.operations(group.symbol) + let encoded = ops.map(Self.encode) + if encoded.count != Set(encoded).count || Set(encoded) != Set(group.operations) { + failures.append("\(group.hall) \(group.symbol): \(encoded.count) vs \(group.operations.count)") + } + if ops.first != SymmetryOperation.identity { failures.append("\(group.symbol): identity not first") } + } catch { + failures.append("\(group.hall) \(group.symbol): \(error)") + } + } + #expect(failures.isEmpty, "\(failures.count) settings differ: \(failures.prefix(20))") + } + + /// A CIF that names its group by Hall symbol alone builds the cell spglib's operations give: with no loop it is + /// expanded with the symbol's group (pymatgen builds the asymmetric unit as P1 here); with a partial loop it is + /// refused naming the symbol and the group's order (pymatgen expands the partial loop silently). + /// RED UNDER: the Hall symbol unread (no loop: refused as missing operations; partial loop: admitted, 2 atoms of 8). + @Test func aCIFNamedByHallSymbolAloneIsReadAndChecked() throws { + let pins = try Self.pins() + #expect(pins.cifs.count == 6) + for planted in pins.cifs { + if let listed = planted.listed { + #expect(throws: CIFImportError.incompleteSymmetryOperationsForSymbol( + symbol: planted.hall, listed: listed, required: planted.groupOrder), "\(planted.name)") { + try CIFImport.read(planted.text) + } + #expect(planted.pymatgenAtoms != planted.truthAtoms, "\(planted.name): pymatgen is the wrong side here") + } else { + let doc = try CIFImport.read(planted.text) + #expect(doc.structure.sites.count == planted.truthAtoms, "\(planted.name)") + #expect(doc.declaredHallSymbol == planted.hall, "\(planted.name)") + #expect(doc.hadSymmetryOperations, "\(planted.name)") + #expect(doc.structure.fileOperations?.count == planted.groupOrder, "\(planted.name)") + #expect(planted.pymatgenAtoms < planted.truthAtoms, "\(planted.name): pymatgen expands as P1") + } + } + // An unreadable Hall symbol with no loop is still refused; "P 1" with no loop is the cell as listed. + let rockSalt = try #require(pins.cifs.first).text + #expect(throws: CIFImportError.missingSymmetryOperations(spaceGroup: "-F 4 2 7")) { + try CIFImport.read(rockSalt.replacingOccurrences(of: "-F 4 2 3", with: "-F 4 2 7")) + } + let p1 = try CIFImport.read(rockSalt.replacingOccurrences(of: "-F 4 2 3", with: "P 1")) + #expect(p1.structure.sites.count == 2) + #expect(!p1.hadSymmetryOperations) + // A Hall symbol smaller than the IT number beside it is refused like a short loop (a mistyped "-P 1"). + let mistyped = rockSalt.replacingOccurrences(of: "-F 4 2 3", with: "-P 1") + "_space_group_IT_number 225\n" + #expect(throws: CIFImportError.incompleteSymmetryOperations( + spaceGroupNumber: 225, declaredName: nil, listed: 2, required: 192)) { try CIFImport.read(mistyped) } + // A loop, even an identity-only one, wins over the Hall symbol: as before, the non-P1 symbol is refused. + let identityLoop = rockSalt + "loop_\n_symmetry_equiv_pos_as_xyz\n'x,y,z'\n" + #expect(throws: CIFImportError.missingSymmetryOperations(spaceGroup: "-F 4 2 3")) { + try CIFImport.read(identityLoop) + } + // A full loop beside the Hall symbol and the IT number reads as before (the loop is expanded). + let full = try HallSymbol.operations("-F 4 2 3").map { "'\($0.xyzString)'" }.joined(separator: "\n") + let doc = try CIFImport.read(rockSalt + "_space_group_IT_number 225\nloop_\n_symmetry_equiv_pos_as_xyz\n" + full + "\n") + #expect(doc.structure.sites.count == 8) + } + + @Test func spellingsAndRefusals() throws { + // The lattice run into the first matrix, a lowercase lattice letter, extra spaces. + let reference = Set(try HallSymbol.operations("-P 2ybc").map(Self.encode)) + #expect(Set(try HallSymbol.operations("-P2ybc").map(Self.encode)) == reference) + #expect(Set(try HallSymbol.operations(" -p 2ybc ").map(Self.encode)) == reference) + #expect(reference.count == 4) + // An origin shift is read mod 12 twelfths. + #expect(Set(try HallSymbol.operations("P 31 2 (0 0 16)").map(Self.encode)) + == Set(try HallSymbol.operations("P 31 2 (0 0 4)").map(Self.encode))) + #expect(try HallSymbol.operations("P 1") == [.identity]) + for bad in ["", "Q 2", "P", "P 5", "P 2q", "P 4 4", "P 2 2 (0 0)", "P 2 2 (0 0 1", "P 3 2 1 1 1", "P 2yb3", "P 3 2 1", "ß 2", "P 2 2 (12 0 99999999999999999999)"] { + #expect(throws: HallSymbolError.self, "\(bad)") { try HallSymbol.operations(bad) } + } + #expect(HallSymbolError.unreadable(symbol: "P 5", reason: "r").description.contains("P 5")) + } +} diff --git a/Tests/Fixtures/README.md b/Tests/Fixtures/README.md index b70d9b7..f9b73f5 100644 --- a/Tests/Fixtures/README.md +++ b/Tests/Fixtures/README.md @@ -1,7 +1,7 @@ # Test fixtures One row per committed fixture file under `Tests/*/Fixtures/`: size, the script under `tools/` that names it (the generator or its -pin script; a few scripts write a whole directory; a script found only by file-name prefix, tool-folder name or test module is marked so), and a note where the origin is not the kit's own pinned reference (every CIF says its source). 52 files. +pin script; a few scripts write a whole directory; a script found only by file-name prefix, tool-folder name or test module is marked so), and a note where the origin is not the kit's own pinned reference (every CIF says its source). 53 files. Licence: the sources and licences are in the next two sections and in `NOTICE`. The pin JSON files are computed by the scripts under `tools/pins/` and ship under the kit's GPL-3.0-only licence. The CIFs were not generated by those scripts: 16 come from the tests of mac4DSTEM 7448401b (GPL-3.0, same author) and 10 were written for this kit (GPL-3.0-only); the pin scripts only read them. The 3 rows marked *third party* keep their own licence. No fixture is a copy of a real dataset: the committed text fixtures carry no local path or personal name (checked by search), and real datasets are read from `$MACEM_DATA` and never copied into the repo. @@ -41,6 +41,7 @@ No fixture is copied from the test data of pymatgen, orix or py4DSTEM. | `DiffractoCoreTests/Fixtures/gold_P1.cif` | 396 B | `tools/pins/cells/pins.py`, `tools/pins/structure-factors/pins.py` | mac4DSTEM tests: from mac4DSTEM 7448401b (GPL-3.0, same author), named in its first comment line | | `DiffractoCoreTests/Fixtures/gold_P1_origin_shifted_exact_decimals.cif` | 588 B | review regression CIF, read by `RefuterRegressionTests` | written for this kit (GPL-3.0-only) | | `DiffractoCoreTests/Fixtures/gold_centring_ops.cif` | 440 B | `tools/pins/cells/pins.py` | mac4DSTEM tests: from mac4DSTEM 7448401b (GPL-3.0, same author), named in its first comment line | +| `DiffractoCoreTests/Fixtures/hall-symbol-pins.json` | 142.7 KB | `tools/pins/cif-symmetry/hall-pins.py` | | | `DiffractoCoreTests/Fixtures/ideal_hcp_P1.cif` | 504 B | `tools/pins/cells/pins.py` | written for this kit (GPL-3.0-only) | | `DiffractoCoreTests/Fixtures/iron_P1_general_position.cif` | 470 B | review regression CIF, read by `RefuterRegressionTests` | written for this kit (GPL-3.0-only) | | `DiffractoCoreTests/Fixtures/magnesium_P1_origin_shifted.cif` | 529 B | review regression CIF, read by `RefuterRegressionTests` | written for this kit (GPL-3.0-only) | diff --git a/docs/parity.md b/docs/parity.md index 12286bd..a1b2cac 100644 --- a/docs/parity.md +++ b/docs/parity.md @@ -94,6 +94,7 @@ and are counted apart. | P33 | orix 0.15.0 `Vector3d.in_fundamental_sector` and Laue groups in the kit frame, 12 class/setting entries, 3 765 poles, 1 500 probe poles per class | `tools/pins/orix/direction-pins.py` -> `orix-direction-pins.json` | `OrixDirectionTests` | orbit membership of the reduced pole against orix's folded pole 1e-5 absolute (was 1e-9; measured 1.1e-15), invariance over the orbit (the kit's own) 1e-9 (measured 9e-16); sampled poles in the zone and pairwise inequivalent; covering radii recorded in `docs/orientation-symmetry.md`. No kit change | | P34 | py4DSTEM f050d207 `Crystal.symmetry_reduce_directions` on real `Crystal`s: 57 centrosymmetric space groups across the 11 Laue classes and both -3m settings, pymatgen 2025.1.9 (the py4DSTEM venv's) operator order, `orientation_plan('auto')` sectors, 151 seeded and designed matrices each | `tools/pins/orientation-symmetry/family-real-pins.py` (py4DSTEM venv) -> `py4dstem-family-real-pins.json`, `PymatgenOperatorTable.swift` | `Py4DSTEMRealFamilyTests` | family entries 1e-7 absolute (was 1e-12; measured 4.4e-16) on 8 607 matrices; `.sortedFractional` (the P28 harness) differs on 139 and 136 of 151 for 2/m and -31m (recorded); wall columns not compared | | P35 | spglib 2.8.0 `get_spacegroup_type` over all 530 Hall settings: every Hermann-Mauguin spelling (short, full, unspaced, alternative settings; 1 048 symbols); pymatgen's primitive C2/m cell with beta = 90 (the fixture records `pymatgen` 2026.9.24, the metapackage; the code that built it is pymatgen-core 2026.10.16, the one on disk in `References/python/orix` and `py4dstem`; regenerated on 2026-10-21, the file is byte-identical) and spglib's operations in that cell | `tools/pins/cif-symmetry/pins.py` -> `Tests/DiffractoCoreTests/Fixtures/cif-symmetry-pins.json` | `CIFSymmetryCompletenessTests` | point-group order x centring equals `CIFImport.spaceGroupOrder` exactly for all 1 048; the primitive cell imports with its atom count (the rows it feeds: sections 1.6 and 1.3; the 0.9.0 numerics are in 2.3 and 2.4) | +| P37 | spglib 2.8.0 `get_symmetry_from_database` over all 530 Hall settings (7 388 operations, centring included) with `get_spacegroup_type(...).hall_symbol`; six planted CIFs that name their group by Hall symbol alone, with the atom count spglib's operations give and the count pymatgen-core 2026.10.16 `CifParser` builds (it reads no Hall symbol: P1 with a warning when there is no loop, the partial loop as given when there is one) | `tools/pins/cif-symmetry/hall-pins.py` -> `Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json` | `HallSymbolTests` | operation sets exact (rotations, translations in twelfths); atom counts exact | pyxem, diffsims and orix are **not pinned clones** here; py4DSTEM is held as its scattering table file (P5) and, for the vector matching and phase mapping of DiffractoOrientation, as a pinned f050d207 environment the pins run (P14, P18). The remaining unexecuted Python APIs below are a checklist, not an additional parity claim. P18 byte-checks the installed crystal.py, crystal_ACOM.py, crystal_viz.py and utils.py against the pinned clone before execution. @@ -158,7 +159,7 @@ matching and phase mapping of DiffractoOrientation, as a pinned f050d207 environ | Python function or option group | DiffractoKit symbol | State | Plan | Upstream tolerance (test file) | How checked | |---|---|---|---|---|---| -| `SpaceGroup.from_int_number(n)` / `SpaceGroup(symbol)` -> `symmetry_ops` (all operations of a space group from its number or symbol), `sg_symbol_from_int_number`, `get_settings` | none (the kit expands only the operations a CIF lists) | not held | study | tests not shipped; `get_orbit` tol=1e-5 (argument) | needed to read a CIF that names a group and lists no operations (ROADMAP item 2, and the CIF-symmetry diagnosis) | +| `SpaceGroup.from_int_number(n)` / `SpaceGroup(symbol)` -> `symmetry_ops` (all operations of a space group from its number or symbol), `sg_symbol_from_int_number`, `get_settings` | none from a number or a Hermann-Mauguin symbol; `HallSymbol.operations(_:)` from a Hall symbol (exact against spglib's 530 settings, P37) | not held | study | tests not shipped; `get_orbit` tol=1e-5 (argument) | needed to read a CIF that names a group by number or Hermann-Mauguin symbol and lists no operations (ROADMAP item 2, and the CIF-symmetry diagnosis); a Hall symbol is read | | order of `SpaceGroup.symmetry_ops` (number of general-position operations) | `CIFImport.spaceGroupOrder(_:)`, `requiredOperationCount(spaceGroup:alphaDeg:betaDeg:gammaDeg:)` | **partly** | study | tests not shipped; assert_allclose defaults | `CIFImportTests` checks Fm-3m 192, C2/m 8, P6_3/mmc 24, R-3m 36 (hand values), not all 230 groups against pymatgen or spglib | | `SpaceGroup.is_compatible(lattice, tol, angle_tol)`, `crystal_system`, `is_subgroup`, `is_supergroup` | none (`UnitCell.metricFamily` classifies a cell; it is not a group-versus-lattice test) | not held | useful | tests not shipped; function arguments `tol=1e-5`, `angle_tol=5` | | | `SpaceGroup.get_orbit(p, tol)`, `get_orbit_and_generators` | none (`CrystalStructure.detectingSymmetry` and `CIFImport` expand sites with the operations they hold) | not held | useful | tests not shipped; function argument `tol=1e-5` | | @@ -177,7 +178,7 @@ matching and phase mapping of DiffractoOrientation, as a pinned f050d207 environ | Python function or option group | DiffractoKit symbol | State | Plan | Upstream tolerance (test file) | How checked | |---|---|---|---|---|---| | `CifParser.from_str(...).parse_structures()` | `CIFImport.read(_:fileBaseName:)` -> `CIFDocument.structure` | **partly** | study | tests not shipped; function arguments `occupancy_tolerance=1.0`, `site_tolerance=1e-4`, `frac_tolerance=1e-4`, `comp_tol=0.01` | P2 on 19 structures: cell, expanded sites, operations equal. Differences by design: the kit reads the subset that defines a structure (cell, atom-site loop, operation loop), refuses what it cannot expand safely (named errors, `CIFImportError`), merges images within the written precision and 0.10 A (pymatgen: `site_tolerance` 1e-4; the kit is looser by design) and detects the symmetry from the expanded cell; no file is read from disk (the caller passes text) | -| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | not held | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number; a symbol-only group is unchecked at the tagged commit (ROADMAP item 1, CIF symmetry, diagnose first). A fixture of spglib's spellings (`tools/pins/cif-symmetry/pins.py`) and tests exist in the working tree, uncommitted, and are not counted here | +| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables) | | `CifParser(filename)`, `CifFile.from_file`, `CifBlock` | none | not held | not planned (`CIFImport` takes text; the caller reads files) | tests not shipped; assert_allclose defaults | | | `CifParser.get_symops` / `SymmOp.from_xyz_str`, `as_xyz_str` | `SymmetryOperation(xyz:)`, `xyzString` | **partly** | study | tests not shipped; assert_allclose defaults | P2 builds the pinned operations from pymatgen's strings; the grammar is mac4DSTEM 7d6fdbd1's with a refusal of singular rotations added (`SymmetryOperationTests`); `xyzString` is not compared with `as_xyz_str` | | `MPRester` summary documents (`structure`, `symmetry`) as a source of structures | `MaterialsProjectImport` (`decode`, `structure(from:)`, `check(_:against:)`), `MaterialsProjectDocument` | **partly** | useful | tests not shipped; assert_allclose defaults | P20, P30: the conventional cell built from the committed MP-shaped inputs equals pymatgen's `SpacegroupAnalyzer` conventional cell (volume 1e-7); the request builder is not run against the service. MP and ICSD database access beyond the request builder is not planned | @@ -364,9 +365,9 @@ ROADMAP "diagnose first" item it says so. 1. Debye-Waller site property (section 1.2): `AtomSite` has no displacement parameter; needed by items 7 and 8. 2. Space group number through spglib (`get_space_group_number`, section 1.3): `spaceGroupNumber` is only what the CIF states. 3. Space group symbol and Hall symbol (`get_space_group_symbol`, `get_hall`, section 1.3): not determined. -4. Space group operations from a number or symbol (`SpaceGroup.from_int_number`, `symmetry_ops`, section 1.4): the kit expands only listed operations. +4. Space group operations from a number or symbol (`SpaceGroup.from_int_number`, `symmetry_ops`, section 1.4): the kit expands only listed operations, or a Hall symbol's. 5. The 32 point groups (`PointGroup.symmetry_ops`, section 1.4): only the 11 Laue groups exist; proper subgroups of non-centrosymmetric groups are missing. -6. CIF symmetry from a named group (section 1.6; ROADMAP item 1, diagnose first): a group named by H-M alone is unchecked, a primitive C-monoclinic cell with beta = 90.00 is falsely refused. +6. CIF symmetry from a named group (section 1.6; ROADMAP item 1, diagnose first): a group named by number or H-M with no loop is refused (a Hall symbol is read, P37). 7. Structure factor with Debye-Waller (`TEMCalculator.cell_intensity`, section 1.7): no displacement factor in `StructureFactors.compute`. 8. Kinematic diffraction pattern API (`TEMCalculator.get_pattern`, diffsims-like, section 1.7; ROADMAP item 4): spots of a beam direction as one call. 9. `match_single_pattern` refinement and `num_matches_return` > 1 (section 2.3; ROADMAP item 5): port only if the study needs them, and say in the table that the scores are not comparable. diff --git a/tools/pins/cif-symmetry/hall-pins.py b/tools/pins/cif-symmetry/hall-pins.py new file mode 100644 index 0000000..37e8fcd --- /dev/null +++ b/tools/pins/cif-symmetry/hall-pins.py @@ -0,0 +1,119 @@ +"""Pins for the Hall-symbol reader and the Hall-only CIF. + +Run: ../References/python/pymatgen/bin/python -I -B tools/pins/cif-symmetry/hall-pins.py +Versions: spglib 2.8.0, pymatgen-core 2026.10.16 (tools/pins/requirements/pymatgen.txt). + +Writes Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json: + groups: for each of the 530 Hall numbers spglib knows, its Hall symbol, its IT number and every operation of the group in + that setting (spglib.get_symmetry_from_database, centring translations included). One operation is 12 + characters: the rotation row by row as "-", "0", "+" and the translation in twelfths as three hex digits, each + in 0 ... 11. The kit must build exactly this set from the symbol text. + cifs: planted CIFs that name their group by Hall symbol alone, with the atom count spglib's operations give (the + truth) and the atom count pymatgen's CifParser builds (it does not read Hall symbols: with no operation loop it + falls back to P1 with a warning; with a partial loop it expands with the loop as given, silently). +""" +import json, pathlib, warnings +import numpy as np +import spglib +from pymatgen.io.cif import CifParser + +out = pathlib.Path(__file__).resolve().parents[3] / "Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json" + + +def encode(r, t): + rot = "".join("-0+"[int(v) + 1] for v in np.asarray(r).ravel()) + scaled = np.asarray(t, float) % 1.0 * 12 + assert np.allclose(scaled, np.rint(scaled), atol=1e-9), t + tw = np.rint(scaled).astype(int) % 12 + return rot + "".join("0123456789ab"[int(v)] for v in tw) + + +groups = [] +for h in range(1, 531): + t = spglib.get_spacegroup_type(h) + d = spglib.get_symmetry_from_database(h) + ops = sorted({encode(r, tr) for r, tr in zip(d["rotations"], d["translations"])}) + assert len(ops) == len(d["rotations"]), h + groups.append({"hall": h, "number": t.number, "symbol": t.hall_symbol, "operations": ops}) + + +def hall_number(symbol): + return next(g["hall"] for g in groups if g["symbol"] == symbol) + + +def xyz(r, t): + parts = [] + for row, tt in zip(r, t): + s = "" + for c, v in zip("xyz", row): + if v == 1: s += ("+" if s else "") + c + elif v == -1: s += "-" + c + tw = int(round(float(tt) % 1.0 * 12)) % 12 + if tw: + from fractions import Fraction + f = Fraction(tw, 12) + s += f"+{f.numerator}/{f.denominator}" + parts.append(s) + return ",".join(parts) + + +def truth(symbol, sites): + d = spglib.get_symmetry_from_database(hall_number(symbol)) + pts = [] + for el, f in sites: + f = np.array(f, float) + for r, t in zip(d["rotations"], d["translations"]): + p = (r @ f + t) % 1.0 + if not any(e == el and np.allclose(((q - p + 0.5) % 1.0) - 0.5, 0, atol=1e-4) for e, q in pts): + pts.append((el, p)) + return len(pts) + + +def cif(name, tag, symbol, cell, ops, sites): + lines = [f"data_{name}", f"{tag} '{symbol}'"] + for k, v in zip(["length_a", "length_b", "length_c", "angle_alpha", "angle_beta", "angle_gamma"], cell): + lines.append(f"_cell_{k} {v}") + if ops is not None: + lines += ["loop_", "_symmetry_equiv_pos_as_xyz"] + [f"'{o}'" for o in ops] + lines += ["loop_", "_atom_site_label", "_atom_site_type_symbol", "_atom_site_fract_x", "_atom_site_fract_y", + "_atom_site_fract_z"] + for i, (el, f) in enumerate(sites): + lines.append(f"{el}{i + 1} {el} {f[0]} {f[1]} {f[2]}") + return "\n".join(lines) + "\n" + + +def pymatgen_atoms(text): + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + p = CifParser.from_str(text) + return len(p.parse_structures(primitive=False, symmetrized=False)[0]), list(p.warnings) + + +cubic_point = [xyz(r, (0, 0, 0)) for r in spglib.get_symmetry_from_database(hall_number("-P 4 2 3"))["rotations"]] +nacl = [("Na", (0, 0, 0)), ("Cl", (0.5, 0.5, 0.5))] +specs = [ + ("rock salt, Hall only, no loop", "_space_group_name_Hall", "-F 4 2 3", (5.64, 5.64, 5.64, 90, 90, 90), None, nacl), + ("rock salt, legacy Hall tag, no loop", "_symmetry_space_group_name_Hall", "-F 4 2 3", + (5.64, 5.64, 5.64, 90, 90, 90), None, nacl), + ("P 21 general site, Hall only, no loop", "_space_group_name_Hall", "P 2yb", (5, 6, 7, 90, 100, 90), None, + [("Si", (0.12, 0.23, 0.34))]), + ("P 31 2 1 with origin shift, Hall only, no loop", "_space_group_name_Hall", "P 31 2 (0 0 4)", + (4.9, 4.9, 5.4, 90, 90, 120), None, [("Si", (0.47, 0.0, 0.0)), ("O", (0.41, 0.27, 0.12))]), + ("rhombohedral axes, Hall only, no loop", "_space_group_name_Hall", "-P 3* 2", (5.1, 5.1, 5.1, 55, 55, 55), None, + [("Al", (0.35, 0.35, 0.35)), ("O", (0.55, 0.95, 0.25))]), + ("rock salt, Hall only, 48 point operations", "_space_group_name_Hall", "-F 4 2 3", (5.64, 5.64, 5.64, 90, 90, 90), + cubic_point, nacl), +] +cifs = [] +for name, tag, symbol, cell, ops, sites in specs: + text = cif("t", tag, symbol, cell, ops, sites) + n, w = pymatgen_atoms(text) + order = len(next(g for g in groups if g["symbol"] == symbol)["operations"]) + cifs.append({"name": name, "text": text, "hall": symbol, "truthAtoms": truth(symbol, sites), "pymatgenAtoms": n, + "pymatgenWarnings": w, "listed": None if ops is None else len(ops), "groupOrder": order}) + +json.dump({"spglib": spglib.__version__, "pymatgen-core": "2026.10.16", "groups": groups, "cifs": cifs}, + open(out, "w"), separators=(",", ":")) +print(out, len(groups), sum(len(g["operations"]) for g in groups)) +for c in cifs: + print(c["name"], c["truthAtoms"], c["pymatgenAtoms"], c["pymatgenWarnings"]) From 7ceb4330e918b642a5b41522c671070441fa1115 Mon Sep 17 00:00:00 2001 From: Paullo9 Date: Sat, 31 Oct 2026 11:34:15 +0100 Subject: [PATCH 2/5] fix!: refuse a CIF operation list that is not its space group A count cannot see wrong operations. After the count checks, the expanding list (a CIF loop, or the Hall group when there is no loop) must now - map the cell onto itself: every rotation keeps R^T G R = G within Policy.operationMetricTolerance (new, default 0.01, per entry relative to sqrt(G_ii G_jj)); - be closed modulo lattice translations (compared to 1e-3; a list whose translations all lie within 0.004 of twelfths is read in twelfths; lists above SymmetryDetection.closureCheckLimit are not checked); - have the crystal class of the IT number the file states (read from the rotation types, so in any setting). A failure throws CIFImportError.inconsistentSymmetryOperations(SymmetryListProblem), naming the operation, the missing product or the two classes. pymatgen-core 2026.10.16 checks none of these and expands the list as given. Diagnosis: Fm-3m listing its 48 conventional-basis operations in the primitive 60-degree cell passed the count (192 / 4) and was expanded; P4/mmm with one operation swapped built 16 atoms of a structure with no symmetry; P4/m declared with the Pmmm list built the Pmmm cell. All three are refused now; spglib groups pin the class table for all 530 settings. Tests that asserted the wrong-basis list was admitted now expect the refusal; a policy fixture whose list was not a group is now one; the absurd-cell test opens the metric check through the policy. BREAKING CHANGE: CIFImportError gains the case inconsistentSymmetryOperations (an exhaustive switch needs it). CIFImport.Policy gains operationMetricTolerance (defaulted, source compatible). Files whose operation list does not fit the cell, is not closed or has another crystal class than the IT number are refused where they were read before; the metric check can be relaxed through the policy. Done: wrong operation lists refused by name. Next: a closed list of the right class with the wrong translations stays unchecked without a Hall symbol (open-items). Co-Authored-By: Claude Opus 5.5 --- .../CIFImport+OperationChecks.swift | 217 ++++++++++++++++++ Sources/DiffractoCore/CIFImport.swift | 23 +- Tests/DiffractoCoreTests/CIFImportTests.swift | 19 +- .../LaueFollowsStructureTests.swift | 11 +- .../OperationListCheckTests.swift | 153 ++++++++++++ Tests/DiffractoCoreTests/PolicyTests.swift | 7 +- .../ToleranceValidationTests.swift | 8 +- docs/open-items.md | 7 +- docs/parity.md | 4 +- 9 files changed, 430 insertions(+), 19 deletions(-) create mode 100644 Sources/DiffractoCore/CIFImport+OperationChecks.swift create mode 100644 Tests/DiffractoCoreTests/OperationListCheckTests.swift diff --git a/Sources/DiffractoCore/CIFImport+OperationChecks.swift b/Sources/DiffractoCore/CIFImport+OperationChecks.swift new file mode 100644 index 0000000..94e4c24 --- /dev/null +++ b/Sources/DiffractoCore/CIFImport+OperationChecks.swift @@ -0,0 +1,217 @@ +// +// CIFImport+OperationChecks.swift +// Role: the checks a CIF's symmetry-operation list must pass beyond its count, because a count cannot see wrong +// operations: every rotation maps the cell onto itself, the list is closed (a group, modulo lattice +// translations), and its rotations form the crystal class of the IT number the file states. Each failure is +// refused by name (`CIFImportError.inconsistentSymmetryOperations`). pymatgen-core 2026.10.16 checks none of +// these and expands the list as given; the kit refuses, as it refuses a short list. +// + +import Foundation +import simd + +/// What is wrong with a symmetry-operation list whose count passed. +public enum SymmetryListProblem: Equatable, Sendable, CustomStringConvertible { + /// The rotation of `operation` does not map the cell onto itself (its metric changes by more than + /// `CIFImport.Policy.operationMetricTolerance`): the list was written for another cell or another setting. + case notACellSymmetry(operation: String) + /// `first` applied after `second` gives `product`, which the list lacks (modulo lattice translations, compared to + /// 1e-3; a list whose translations all lie within 0.004 of twelfths is read in twelfths): the list is not a group. + case notClosed(first: String, second: String, product: String) + /// The listed rotations form the crystal class `listed` (nil: none of the 32), but space group No. `spaceGroupNumber` + /// belongs to class `required`. + case wrongCrystalClass(spaceGroupNumber: Int, listed: String?, required: String) + + public var description: String { + switch self { + case .notACellSymmetry(let op): + return "the operation \"\(op)\" does not map the cell onto itself, so the list belongs to another cell or " + + "setting" + case .notClosed(let first, let second, let product): + return "\"\(first)\" after \"\(second)\" gives \"\(product)\", which the list lacks, so the list is not a " + + "space group (an operation is wrong or missing)" + case .wrongCrystalClass(let number, let listed, let required): + return "its rotations form the crystal class \(listed ?? "of none of the 32 point groups"), but space group " + + "No. \(number) belongs to class \(required)" + } + } +} + +extension CIFImport { + + /// The crystal class (short point-group symbol) of each range of IT numbers. + private static let crystalClasses: [(numbers: ClosedRange, symbol: String)] = [ + (1...1, "1"), (2...2, "-1"), (3...5, "2"), (6...9, "m"), (10...15, "2/m"), (16...24, "222"), (25...46, "mm2"), + (47...74, "mmm"), (75...80, "4"), (81...82, "-4"), (83...88, "4/m"), (89...98, "422"), (99...110, "4mm"), + (111...122, "-42m"), (123...142, "4/mmm"), (143...146, "3"), (147...148, "-3"), (149...155, "32"), + (156...161, "3m"), (162...167, "-3m"), (168...173, "6"), (174...174, "-6"), (175...176, "6/m"), + (177...182, "622"), (183...186, "6mm"), (187...190, "-6m2"), (191...194, "6/mmm"), (195...199, "23"), + (200...206, "m-3"), (207...214, "432"), (215...220, "-43m"), (221...230, "m-3m"), + ] + + /// How many elements of each rotation type a crystal class holds, in the order 1, 2, 3, 4, 6, -1, m, -3, -4, -6. + /// The type of a rotation is read from its determinant and trace, which no change of basis alters, so the class is + /// found in any setting. The 32 classes have 32 different signatures. + private static let classSignatures: [[Int]: String] = [ + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]: "1", [1, 0, 0, 0, 0, 1, 0, 0, 0, 0]: "-1", + [1, 1, 0, 0, 0, 0, 0, 0, 0, 0]: "2", [1, 0, 0, 0, 0, 0, 1, 0, 0, 0]: "m", [1, 1, 0, 0, 0, 1, 1, 0, 0, 0]: "2/m", + [1, 3, 0, 0, 0, 0, 0, 0, 0, 0]: "222", [1, 1, 0, 0, 0, 0, 2, 0, 0, 0]: "mm2", + [1, 3, 0, 0, 0, 1, 3, 0, 0, 0]: "mmm", + [1, 1, 0, 2, 0, 0, 0, 0, 0, 0]: "4", [1, 1, 0, 0, 0, 0, 0, 0, 2, 0]: "-4", [1, 1, 0, 2, 0, 1, 1, 0, 2, 0]: "4/m", + [1, 5, 0, 2, 0, 0, 0, 0, 0, 0]: "422", [1, 1, 0, 2, 0, 0, 4, 0, 0, 0]: "4mm", + [1, 3, 0, 0, 0, 0, 2, 0, 2, 0]: "-42m", [1, 5, 0, 2, 0, 1, 5, 0, 2, 0]: "4/mmm", + [1, 0, 2, 0, 0, 0, 0, 0, 0, 0]: "3", [1, 0, 2, 0, 0, 1, 0, 2, 0, 0]: "-3", [1, 3, 2, 0, 0, 0, 0, 0, 0, 0]: "32", + [1, 0, 2, 0, 0, 0, 3, 0, 0, 0]: "3m", [1, 3, 2, 0, 0, 1, 3, 2, 0, 0]: "-3m", + [1, 1, 2, 0, 2, 0, 0, 0, 0, 0]: "6", [1, 0, 2, 0, 0, 0, 1, 0, 0, 2]: "-6", [1, 1, 2, 0, 2, 1, 1, 2, 0, 2]: "6/m", + [1, 7, 2, 0, 2, 0, 0, 0, 0, 0]: "622", [1, 1, 2, 0, 2, 0, 6, 0, 0, 0]: "6mm", + [1, 3, 2, 0, 0, 0, 4, 0, 0, 2]: "-6m2", [1, 7, 2, 0, 2, 1, 7, 2, 0, 2]: "6/mmm", + [1, 3, 8, 0, 0, 0, 0, 0, 0, 0]: "23", [1, 3, 8, 0, 0, 1, 3, 8, 0, 0]: "m-3", + [1, 9, 8, 6, 0, 0, 0, 0, 0, 0]: "432", [1, 3, 8, 0, 0, 0, 6, 0, 6, 0]: "-43m", + [1, 9, 8, 6, 0, 1, 9, 8, 6, 0]: "m-3m", + ] + + /// The crystal class of space group `number` (1 ... 230); nil outside. + package static func crystalClass(spaceGroup number: Int) -> String? { + crystalClasses.first { $0.numbers.contains(number) }?.symbol + } + + /// The crystal class the distinct rotations of `rotations` form; nil when they are not one of the 32 point groups. + package static func crystalClass(of rotations: [IntegerMatrix]) -> String? { + var signature = [Int](repeating: 0, count: 10) + for rotation in Set(rotations) { + let trace = rotation[0, 0] + rotation[1, 1] + rotation[2, 2] + let slot: Int? + switch (rotation.determinant, trace) { + case (1, 3): slot = 0 + case (1, -1): slot = 1 + case (1, 0): slot = 2 + case (1, 1): slot = 3 + case (1, 2): slot = 4 + case (-1, -3): slot = 5 + case (-1, 1): slot = 6 + case (-1, 0): slot = 7 + case (-1, -1): slot = 8 + case (-1, -2): slot = 9 + default: slot = nil + } + guard let slot else { return nil } + signature[slot] += 1 + } + return classSignatures[signature] + } + + /// The first problem of an expanding operation list, or nil: a rotation that is not an isometry of `cell` (an entry of + /// RᵀGR − G above `metricTolerance` · sqrt(G_ii G_jj)), a product the list lacks (lists longer than + /// `SymmetryDetection.closureCheckLimit` are not checked for closure), or a crystal class other than that of + /// `spaceGroupNumber`. + package static func operationListProblem(_ ops: [SymmetryOperation], cell: UnitCell, spaceGroupNumber: Int?, + metricTolerance: Double) -> SymmetryListProblem? { + // Metric: R^T G R = G for every rotation, each entry relative to sqrt(G_ii G_jj) (scale-free on every axis). + let lattice = cell.realLattice + let g = (0..<3).map { i in (0..<3).map { j in simd_dot(lattice[i], lattice[j]) } } + let diagonal = [g[0][0], g[1][1], g[2][2]] + let tolerance = metricTolerance.isFinite && metricTolerance >= 0 ? metricTolerance : 0 + if diagonal.allSatisfy({ $0.isFinite && $0 > 0 }) { + var checked = Set() + for op in ops where checked.insert(op.rotation).inserted { + let r = op.rotation + var worst = 0.0 + for i in 0..<3 { + for j in 0..<3 { + var sum = 0.0 + for k in 0..<3 { + for l in 0..<3 where r[k, i] != 0 && r[l, j] != 0 { + sum += Double(r[k, i] * r[l, j]) * g[k][l] + } + } + worst = max(worst, abs(sum - g[i][j]) / (diagonal[i] * diagonal[j]).squareRoot()) + } + } + if !(worst <= tolerance) { + return .notACellSymmetry(operation: op.xyzString) + } + } + } + + // Closure modulo lattice translations. When every translation of the list lies within 0.004 of a twelfth (a + // hand-rounded list: 0.33, 0.67, 0.17), all are read as those twelfths, so they compose exactly; otherwise (an + // origin-shifted list with 0.74 or 0.11, a test shift of 0.008) they are kept and compared to 1e-3. Snapping + // only part of a list would break the products of the rest. Rotations get small integer ids and a product + // table; a key packs the id and the three translations in thousandths into one Int. + func nearTwelfth(_ value: Double) -> Bool { + guard value.isFinite else { return false } + let scaled = (value - value.rounded(.down)) * 12 + return abs(scaled - scaled.rounded()) <= 0.004 * 12 + } + let roundedTwelfths = ops.allSatisfy { nearTwelfth($0.translation.x) && nearTwelfth($0.translation.y) + && nearTwelfth($0.translation.z) } + func snapped(_ value: Double) -> Double { + guard value.isFinite else { return 0 } + let wrapped = value - value.rounded(.down) + return roundedTwelfths ? (wrapped * 12).rounded() / 12 : wrapped + } + func milli(_ value: Double) -> Int { + guard value.isFinite else { return 0 } + let wrapped = value - value.rounded(.down) + return Int((wrapped * 1000).rounded()) % 1000 + } + var rotationIDs: [IntegerMatrix: Int] = [:] + var rotations: [IntegerMatrix] = [] + func key(_ id: Int, _ t: SIMD3) -> Int { + ((id * 1000 + milli(t.x)) * 1000 + milli(t.y)) * 1000 + milli(t.z) + } + var listed = Set() + var distinct: [(op: SymmetryOperation, id: Int)] = [] + for raw in ops { + let op = SymmetryOperation(rotation: raw.rotation, + translation: SIMD3(snapped(raw.translation.x), snapped(raw.translation.y), + snapped(raw.translation.z))) + let id: Int + if let known = rotationIDs[op.rotation] { id = known } else { + id = rotations.count + rotationIDs[op.rotation] = id + rotations.append(op.rotation) + } + if listed.insert(key(id, op.translation)).inserted { distinct.append((op, id)) } + } + func isListed(_ id: Int, _ t: SIMD3) -> Bool { + if listed.contains(key(id, t)) { return true } + let m = SIMD3(milli(t.x), milli(t.y), milli(t.z)) + for dx in -1...1 { + for dy in -1...1 { + for dz in -1...1 where dx != 0 || dy != 0 || dz != 0 { + let packed = ((id * 1000 + (m.x + dx + 1000) % 1000) * 1000 + (m.y + dy + 1000) % 1000) * 1000 + + (m.z + dz + 1000) % 1000 + if listed.contains(packed) { return true } + } + } + } + return false + } + func notClosed(_ first: SymmetryOperation, _ second: SymmetryOperation) -> SymmetryListProblem { + let product = first.composed(with: second) + return .notClosed(first: first.xyzString, second: second.xyzString, + product: SymmetryOperation(rotation: product.rotation, + translation: product.translationMod1).xyzString) + } + if distinct.count <= SymmetryDetection.closureCheckLimit { + let productIDs = rotations.map { a in rotations.map { b in rotationIDs[a.multiplied(by: b)] } } + for first in distinct { + for second in distinct { + guard let id = productIDs[first.id][second.id] else { return notClosed(first.op, second.op) } + let t = first.op.rotation.apply(second.op.translation) + first.op.translation + if !isListed(id, t) { return notClosed(first.op, second.op) } + } + } + } + + // Crystal class against the IT number. + if let number = spaceGroupNumber, let required = crystalClass(spaceGroup: number) { + let listedClass = crystalClass(of: rotations) + if listedClass != required { + return .wrongCrystalClass(spaceGroupNumber: number, listed: listedClass, required: required) + } + } + return nil + } +} diff --git a/Sources/DiffractoCore/CIFImport.swift b/Sources/DiffractoCore/CIFImport.swift index b9a5fef..90f4e4e 100644 --- a/Sources/DiffractoCore/CIFImport.swift +++ b/Sources/DiffractoCore/CIFImport.swift @@ -46,6 +46,9 @@ public enum CIFImportError: Error, Equatable, Sendable, CustomStringConvertible case incompleteSymmetryOperationsForSymbol(symbol: String, listed: Int, required: Int) /// A `data_` block that defines no structure carries a symmetry-operation loop while another block defines one. case symmetryOperationsOutsideStructure(blockNames: [String]) + /// The operations are enough in number but cannot be the file's space group: one does not map the cell onto itself, + /// the list is not closed, or its crystal class is not the IT number's (``SymmetryListProblem``). + case inconsistentSymmetryOperations(SymmetryListProblem) public var description: String { switch self { @@ -91,6 +94,10 @@ public enum CIFImportError: Error, Equatable, Sendable, CustomStringConvertible return "The CIF has a symmetry-operation loop in a data_ block that holds no structure " + "(\(names.joined(separator: ", "))). Reading the file as one crystal would apply those operations to " + "another block's atoms. Move the loop into the structure's own data_ block, or split the file." + case .inconsistentSymmetryOperations(let problem): + return "The CIF's symmetry operations cannot be its space group: \(problem). Expanding the atom sites with " + + "them would build a wrong structure, so the file is refused. Re-export the CIF with the operation " + + "loop of its own cell and setting, or supply a P1 file that lists every atom in the cell." } } } @@ -141,6 +148,11 @@ public enum CIFImport { public var rightAngleToleranceDeg: Double /// The largest number a symmetry operation's text may hold. Default 1000. public var maximumOperationMagnitude: Double + /// How far a listed rotation may change the cell metric and still count as a symmetry of the cell: each entry of + /// |RᵀGR − G| over sqrt(G_ii G_jj). Default 0.01 (about 0.6 degrees in an angle, 0.5 % in a length; an operation + /// of another cell or setting changes it by tens of percent). Only this check of the operation list has a knob: + /// closure and the crystal class are not tolerances and cannot be turned off. + public var operationMetricTolerance: Double /// How two positions are called the same site in the symmetry detection. Default fractional 5e-3. public var positionTolerance: SymmetryDetection.Tolerance /// The metric family tolerances (relative on lengths, degrees on angles). Default 1e-9 both. @@ -154,6 +166,7 @@ public enum CIFImport { public init(maximumMergeDistance: Double = 0.10, minimumMergeTolerance: Double = 1e-6, maximumCoordinateHalfStep: Double = 1e-2, rightAngleToleranceDeg: Double = 0.05, maximumOperationMagnitude: Double = SymmetryOperation.defaultMaximumMagnitude, + operationMetricTolerance: Double = 0.01, positionTolerance: SymmetryDetection.Tolerance = .default, metricLengthTolerance: Double = SymmetryDetection.defaultMetricLengthTolerance, metricAngleToleranceDeg: Double = SymmetryDetection.defaultMetricAngleToleranceDeg, @@ -164,6 +177,7 @@ public enum CIFImport { self.maximumCoordinateHalfStep = maximumCoordinateHalfStep self.rightAngleToleranceDeg = rightAngleToleranceDeg self.maximumOperationMagnitude = maximumOperationMagnitude + self.operationMetricTolerance = operationMetricTolerance self.positionTolerance = positionTolerance self.metricLengthTolerance = metricLengthTolerance self.metricAngleToleranceDeg = metricAngleToleranceDeg @@ -442,7 +456,14 @@ public enum CIFImport { throw .incompleteSymmetryOperationsForSymbol(symbol: hallSymbol, listed: listed, required: hallOperations.count) } - let lattice = UnitCell(a: a, b: b, c: c, alphaDeg: alpha, betaDeg: beta, gammaDeg: gamma).realLattice + // A count cannot see wrong operations: each must map the cell onto itself, the list must be closed, and + // its crystal class must be the IT number's (a Hall group is closed, but its setting may not fit the cell). + let unitCell = UnitCell(a: a, b: b, c: c, alphaDeg: alpha, betaDeg: beta, gammaDeg: gamma) + if let problem = operationListProblem(ops, cell: unitCell, spaceGroupNumber: spaceGroupNumber, + metricTolerance: policy.operationMetricTolerance) { + throw .inconsistentSymmetryOperations(problem) + } + let lattice = unitCell.realLattice sites = expand(baseSites, using: ops, latReal: lattice, policy: policy) var distinct: [SymmetryOperation] = [] for op in ops where !distinct.contains(where: { $0.isEquivalent(to: op) }) { diff --git a/Tests/DiffractoCoreTests/CIFImportTests.swift b/Tests/DiffractoCoreTests/CIFImportTests.swift index 31401c9..3f2c3b0 100644 --- a/Tests/DiffractoCoreTests/CIFImportTests.swift +++ b/Tests/DiffractoCoreTests/CIFImportTests.swift @@ -284,8 +284,9 @@ struct CIFImportTests { #expect(refusal(garbled) == .unsupportedSymmetryOperation("1000000000000000000000x,y,z")) } - /// Fm-3m listing only its 48 point operations is refused naming the gap; in a primitive (rhombohedral) cell it is - /// not; duplicated rows do not pad the list. + /// Fm-3m listing only its 48 point operations is refused naming the gap; duplicated rows do not pad the list. In a + /// primitive (rhombohedral) cell 48 is enough, but these conventional-basis operations do not map that cell onto + /// itself and are refused by name (`OperationListCheckTests` has the right primitive list). @Test func testIncompleteOperationListsAreRefused() throws { let pointOps = PointSymmetry.holohedry(of: .cubic).rotations.map { SymmetryOperation(rotation: $0).xyzString } func loop(_ ops: [String]) -> String { "loop_\n_symmetry_equiv_pos_as_xyz\n" + ops.map { "'\($0)'" }.joined(separator: "\n") + "\n" } @@ -295,8 +296,8 @@ struct CIFImportTests { #expect(refusal(header + cell + loop(pointOps) + atoms) == .incompleteSymmetryOperations(spaceGroupNumber: 225, declaredName: "F m -3 m", listed: 48, required: 192)) #expect(refusal(header + cell + loop(pointOps + pointOps) + atoms) == .incompleteSymmetryOperations(spaceGroupNumber: 225, declaredName: "F m -3 m", listed: 48, required: 192)) let primitiveCell = "_cell_length_a 2.977\n_cell_length_b 2.977\n_cell_length_c 2.977\n_cell_angle_alpha 60\n_cell_angle_beta 60\n_cell_angle_gamma 60\n" - let primitive = try CIFImport.read(header + primitiveCell + loop(pointOps) + atoms) - #expect(primitive.structure.sites.count == 2) + guard case .inconsistentSymmetryOperations(.notACellSymmetry)? = refusal(header + primitiveCell + loop(pointOps) + atoms) + else { Issue.record("conventional-basis operations admitted in a primitive cell"); return } #expect(CIFImport.spaceGroupOrder(225) == 192) #expect(CIFImport.spaceGroupOrder(12) == 8) #expect(CIFImport.spaceGroupOrder(194) == 24) @@ -445,9 +446,15 @@ struct CIFSymmetryCompletenessTests { } catch { #expect(error == .incompleteSymmetryOperationsForSymbol(symbol: "F m -3 m", listed: 48, required: 192)) } - // A symbol the parser cannot read stays unchecked (as before), and the primitive rhombohedral listing is admitted. + // A symbol the parser cannot read stays unchecked for its count (as before). In the primitive rhombohedral cell 48 + // passes the count (192 / 4); these conventional-basis operations are then refused as no symmetry of that cell. let primitiveCell = "_cell_length_a 2.977\n_cell_length_b 2.977\n_cell_length_c 2.977\n_cell_angle_alpha 60\n_cell_angle_beta 60\n_cell_angle_gamma 60\n" - #expect(try CIFImport.read(header + primitiveCell + loop + atoms).structure.sites.count == 2) + do { + _ = try CIFImport.read(header + primitiveCell + loop + atoms) + Issue.record("conventional-basis operations admitted in a primitive cell") + } catch { + guard case .inconsistentSymmetryOperations(.notACellSymmetry) = error else { Issue.record("\(error)"); return } + } let unreadable = header.replacingOccurrences(of: "F m -3 m", with: "F banana") #expect(try CIFImport.read(unreadable + cell + loop + atoms).structure.sites.count > 0) } diff --git a/Tests/DiffractoCoreTests/LaueFollowsStructureTests.swift b/Tests/DiffractoCoreTests/LaueFollowsStructureTests.swift index a343f55..3bf8ef0 100644 --- a/Tests/DiffractoCoreTests/LaueFollowsStructureTests.swift +++ b/Tests/DiffractoCoreTests/LaueFollowsStructureTests.swift @@ -77,8 +77,10 @@ import DiffractoCore } /// A file that lists the 48 signed permutations of x, y, z literally (written in the primitive basis) for the - /// 60-degree cell: not all of them are symmetries of that lattice, but the atoms and the lattice (an fcc lattice) - /// have the full cubic group, so the class is m-3m. + /// 60-degree cell: not all of them are symmetries of that lattice. On these two special positions the expansion + /// happened to be right, on a general position it is not, so the list is refused by name; with the metric check + /// opened (a policy) the atoms and the fcc lattice still give the class m-3m. + /// RED UNDER: no metric check (the list was admitted whatever the sites). @Test func literalSignedPermutationsInAPrimitiveCellStillGiveTheStructuresClass() throws { var ops: [String] = [] for p in [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] { @@ -90,7 +92,10 @@ import DiffractoCore for a in [4.212, 4.212 / 2.0.squareRoot()] { let text = cif(name: "MgOliteral", a: a, b: a, c: a, alpha: 60, beta: 60, gamma: 60, ops: ops, atoms: [("Mg", 0, 0, 0), ("O", 0.5, 0.5, 0.5)]) - let doc = try CIFImport.read(text, fileBaseName: "t") + #expect(throws: CIFImportError.inconsistentSymmetryOperations(.notACellSymmetry(operation: "-x,y,z"))) { + try CIFImport.read(text, fileBaseName: "t") + } + let doc = try CIFImport.read(text, fileBaseName: "t", policy: CIFImport.Policy(operationMetricTolerance: 10)) #expect(doc.structure.laueClass == .mThreeBarM, "a = \(a)") } } diff --git a/Tests/DiffractoCoreTests/OperationListCheckTests.swift b/Tests/DiffractoCoreTests/OperationListCheckTests.swift new file mode 100644 index 0000000..4cfd667 --- /dev/null +++ b/Tests/DiffractoCoreTests/OperationListCheckTests.swift @@ -0,0 +1,153 @@ +// +// OperationListCheckTests.swift +// A listed operation list whose count is right but whose operations are wrong: not symmetries of the cell, not closed, +// or of another crystal class than the IT number's. The groups are spglib 2.8.0's (`hall-symbol-pins.json`, +// tools/pins/cif-symmetry/hall-pins.py). pymatgen-core 2026.10.16 `CifParser` admits every one of these lists and +// expands it as given. +// + +import DiffractoKitTestSupport +import Foundation +import Testing +@testable import DiffractoCore + +struct OperationListCheckTests { + /// The fixture's 12-character operation: rotation as - 0 +, translation in twelfths as hex. + static func decode(_ code: String) -> SymmetryOperation { + let c = Array(code) + let entries = c[0..<9].map { $0 == "-" ? -1 : $0 == "+" ? 1 : 0 } + let rotation = IntegerMatrix(SIMD3(entries[0], entries[1], entries[2]), SIMD3(entries[3], entries[4], entries[5]), + SIMD3(entries[6], entries[7], entries[8])) + let t = c[9..<12].map { Double(Int(String($0), radix: 16) ?? 0) / 12 } + return SymmetryOperation(rotation: rotation, translation: SIMD3(t[0], t[1], t[2])) + } + + static func group(_ symbol: String) throws -> [SymmetryOperation] { + let pins = try HallSymbolTests.pins() + return try #require(pins.groups.first { $0.symbol == symbol }).operations.map(decode) + } + + static func cif(number: Int?, cell: [Double], ops: [String], sites: [(String, Double, Double, Double)]) -> String { + var s = "data_t\n" + if let number { s += "_symmetry_Int_Tables_number \(number)\n" } + for (tag, v) in zip(["length_a", "length_b", "length_c", "angle_alpha", "angle_beta", "angle_gamma"], cell) { + s += "_cell_\(tag) \(v)\n" + } + s += "loop_\n_symmetry_equiv_pos_as_xyz\n" + ops.map { "'\($0)'" }.joined(separator: "\n") + "\n" + s += "loop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\n" + for (i, site) in sites.enumerated() { s += "\(site.0)\(i) \(site.0) \(site.1) \(site.2) \(site.3)\n" } + return s + } + + static func problem(_ text: String) -> SymmetryListProblem? { + do { _ = try CIFImport.read(text); return nil } catch { + guard case .inconsistentSymmetryOperations(let p) = error else { return nil } + return p + } + } + + static let general: [(String, Double, Double, Double)] = [("Si", 0.1, 0.2, 0.3)] + + /// The crystal class read from the rotations equals the class of the IT number for every one of spglib's 530 + /// settings (centred, rhombohedral and origin-shifted ones included), and every IT number has a class. + @Test func theCrystalClassOfEverySpglibSettingIsItsNumbers() throws { + let pins = try HallSymbolTests.pins() + var failures: [String] = [] + for g in pins.groups { + let listed = CIFImport.crystalClass(of: g.operations.map { Self.decode($0).rotation }) + let required = CIFImport.crystalClass(spaceGroup: g.number) + if listed == nil || listed != required { failures.append("\(g.symbol) No. \(g.number): \(listed ?? "nil") vs \(required ?? "nil")") } + } + #expect(failures.isEmpty, "\(failures.prefix(10))") + #expect((1...230).allSatisfy { CIFImport.crystalClass(spaceGroup: $0) != nil }) + #expect(CIFImport.crystalClass(spaceGroup: 231) == nil) + #expect(Set((1...230).compactMap { CIFImport.crystalClass(spaceGroup: $0) }).count == 32) + } + + /// Fm-3m in its primitive 60-degree cell: the 48 operations listed in the conventional basis pass the count (192 / 4) + /// but do not map the cell onto itself, and are refused by name; spglib's operations brought into that basis are + /// admitted with the 48 images of a general site. RED UNDER: no metric check (the wrong list was expanded). + @Test func operationsOfAnotherBasisAreRefused() throws { + let cell = [10.0, 10.0, 10.0, 60, 60, 60] // large enough for 48 images of a general site + let pointOps = try Self.group("-P 4 2 3").map(\.xyzString) + guard case .notACellSymmetry? = Self.problem(Self.cif(number: 225, cell: cell, ops: pointOps, sites: Self.general)) + else { Issue.record("conventional-basis operations admitted in the primitive cell"); return } + + // x_prim = P^-1 x_conv with P = [[0,1,1],[1,0,1],[1,1,0]] / 2: R' = P^-1 R P, t' = P^-1 t. + let p: [[Double]] = [[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]] + let pInverse: [[Double]] = [[-1, 1, 1], [1, -1, 1], [1, 1, -1]] + func mul(_ a: [[Double]], _ b: [[Double]]) -> [[Double]] { + (0..<3).map { i in (0..<3).map { j in (0..<3).reduce(0) { $0 + a[i][$1] * b[$1][j] } } } + } + var primitiveOps = Set() + for op in try Self.group("-F 4 2 3") { + let r = (0..<3).map { i in (0..<3).map { j in Double(op.rotation[i, j]) } } + let rp = mul(mul(pInverse, r), p).map { $0.map { Int($0.rounded()) } } + let t = (0..<3).map { i in (0..<3).reduce(0.0) { $0 + pInverse[i][$1] * op.translation[$1] } } + let prim = SymmetryOperation(rotation: IntegerMatrix(SIMD3(rp[0]), SIMD3(rp[1]), SIMD3(rp[2])), + translation: wrapFractional(SIMD3(t[0], t[1], t[2]))) + primitiveOps.insert(prim.xyzString) + } + #expect(primitiveOps.count == 48) + let doc = try CIFImport.read(Self.cif(number: 225, cell: cell, ops: primitiveOps.sorted(), sites: Self.general)) + #expect(doc.structure.sites.count == 48) + } + + /// P4/mmm with one of its 16 operations swapped for an operation of another group: the count is right, the list is + /// not closed, and the refusal names a missing product. RED UNDER: no closure check (16 atoms of a structure with no + /// symmetry were built). + @Test func aListThatIsNotClosedIsRefused() throws { + let ops = try Self.group("-P 4 2").map(\.xyzString) + #expect(ops.count == 16 && ops.contains("-y,x,z")) + let swapped = ops.filter { $0 != "-y,x,z" } + ["y,x+1/2,z"] + let cell = [4.0, 4.0, 5.0, 90, 90, 90] + guard case .notClosed? = Self.problem(Self.cif(number: 123, cell: cell, ops: swapped, sites: Self.general)) + else { Issue.record("a list that is not a group was admitted"); return } + #expect(try CIFImport.read(Self.cif(number: 123, cell: cell, ops: ops, sites: Self.general)).structure.sites.count == 16) + } + + /// A hand-rounded list (P3_1 with z+0.33 and z+0.67, which compose to z+0.66) is still a group: translations within + /// 0.004 of a twelfth (all of them) are read as twelfths. An a-b swap in an elongated cell is no symmetry of it. + @Test func roundedTranslationsAreClosedAndElongatedCellsAreJudgedPerAxis() throws { + let p31 = ["x,y,z", "-y,x-y,z+0.33", "-x+y,-x,z+0.67"] + let hexagonal = [5.0, 5.0, 7.0, 90, 90, 120] + #expect(try CIFImport.read(Self.cif(number: 144, cell: hexagonal, ops: p31, sites: Self.general)).structure.sites.count == 3) + let swap = ["x,y,z", "y,x,-z"] + guard case .notACellSymmetry? = Self.problem(Self.cif(number: nil, cell: [3.0, 4.0, 50.0, 90, 90, 90], ops: swap, + sites: Self.general)) + else { Issue.record("an a-b swap was admitted in a 3 x 4 x 50 cell"); return } + } + + /// A file that declares P4/m (No. 83) and lists the 8 operations of Pmmm: closed, the right count, symmetries of the + /// tetragonal cell, but of class mmm, not 4/m. RED UNDER: no class check (the Pmmm cell was built). + @Test func aListOfAnotherCrystalClassIsRefused() throws { + let cell = [4.0, 4.0, 5.0, 90, 90, 90] + let pmmm = try Self.group("-P 2 2").map(\.xyzString) + #expect(Self.problem(Self.cif(number: 83, cell: cell, ops: pmmm, sites: Self.general)) + == .wrongCrystalClass(spaceGroupNumber: 83, listed: "mmm", required: "4/m")) + let p4m = try Self.group("-P 4").map(\.xyzString) + #expect(try CIFImport.read(Self.cif(number: 83, cell: cell, ops: p4m, sites: Self.general)).structure.sites.count == 8) + } + + /// A Hall symbol in hexagonal axes (`-R 3 2"`) on a cell written in rhombohedral axes: the group is closed, but its + /// three-fold is no symmetry of that cell, so the file is refused rather than given R-centring images. + @Test func aHallSettingThatDoesNotFitTheCellIsRefused() throws { + var text = "data_t\n_space_group_name_Hall '-R 3 2\"'\n" + for (tag, v) in zip(["length_a", "length_b", "length_c", "angle_alpha", "angle_beta", "angle_gamma"], + ["5.1", "5.1", "5.1", "55", "55", "55"]) { text += "_cell_\(tag) \(v)\n" } + text += "loop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\n" + text += "Al1 Al 0.35 0.35 0.35\n" + guard case .notACellSymmetry? = Self.problem(text) else { Issue.record("a Hall setting of another cell was used"); return } + let rhombohedral = text.replacingOccurrences(of: "-R 3 2\"", with: "-P 3* 2") + #expect(try CIFImport.read(rhombohedral).structure.sites.count == 2) + } + + @Test func theProblemsSayWhatIsWrong() { + #expect(SymmetryListProblem.notACellSymmetry(operation: "-x,y,z").description.contains("-x,y,z")) + #expect(SymmetryListProblem.notClosed(first: "a", second: "b", product: "c").description.contains("\"c\"")) + #expect(SymmetryListProblem.wrongCrystalClass(spaceGroupNumber: 83, listed: "mmm", required: "4/m").description + .contains("4/m")) + #expect(CIFImportError.inconsistentSymmetryOperations(.notACellSymmetry(operation: "-x,y,z")).description + .contains("refused")) + } +} diff --git a/Tests/DiffractoCoreTests/PolicyTests.swift b/Tests/DiffractoCoreTests/PolicyTests.swift index 3a83b4b..8528bb9 100644 --- a/Tests/DiffractoCoreTests/PolicyTests.swift +++ b/Tests/DiffractoCoreTests/PolicyTests.swift @@ -288,8 +288,8 @@ struct DetectionPolicyTests { struct CIFImportPolicyTests { typealias Policy = CIFImport.Policy - /// A 10 Å cubic cell with one site written to one decimal and a second operation that moves it by 0.008 (0.08 Å): the two - /// images are the same site within the rounding error and 0.10 Å. + /// A 10 Å cubic cell with one site written to one decimal and a mirror at x = 0.304 that moves it by 0.008 (0.08 Å; a + /// closed list, as the import requires): the two images are the same site within the rounding error and 0.10 Å. static let nearlyCoincident = """ data_near _cell_length_a 10.0 @@ -301,7 +301,7 @@ struct CIFImportPolicyTests { loop_ _symmetry_equiv_pos_as_xyz 'x,y,z' - 'x+0.008,y,z' + '-x+0.608,y,z' loop_ _atom_site_label _atom_site_type_symbol @@ -341,6 +341,7 @@ struct CIFImportPolicyTests { #expect(p.maximumCoordinateHalfStep == 1e-2) #expect(p.rightAngleToleranceDeg == 0.05) #expect(p.maximumOperationMagnitude == 1000) + #expect(p.operationMetricTolerance == 0.01) #expect(p.positionTolerance == .default) #expect(p.metricLengthTolerance == 1e-9) #expect(p.metricAngleToleranceDeg == 1e-9) diff --git a/Tests/DiffractoCoreTests/ToleranceValidationTests.swift b/Tests/DiffractoCoreTests/ToleranceValidationTests.swift index 9d6252a..4b0b98a 100644 --- a/Tests/DiffractoCoreTests/ToleranceValidationTests.swift +++ b/Tests/DiffractoCoreTests/ToleranceValidationTests.swift @@ -164,6 +164,10 @@ struct ToleranceValidationTests { // MARK: - Absurd cells and the Niggli epsilon struct AbsurdCellTests { + /// With a no longer equal to b the hexagonal operations are not symmetries of the cell, and the import refuses them + /// (`inconsistentSymmetryOperations`). These cases are about the conventional route, so that check is opened. + static let anyMetric = CIFImport.Policy(operationMetricTolerance: 1e300) + /// The fluorapatite file with its first cell length replaced. static func fluorapatite(a: String) throws -> String { let text = try Fixtures.text("fluorapatite_P63m.cif") @@ -180,14 +184,14 @@ struct AbsurdCellTests { @Test func anAbsurdCifNeverTraps() throws { for a in ["1e-9", "1e-7", "1e-5", "1e-3", "1e-12", "1e-15", "1e-300"] { do { - let document = try CIFImport.read(try Self.fluorapatite(a: a)) + let document = try CIFImport.read(try Self.fluorapatite(a: a), policy: Self.anyMetric) #expect(document.structure.conventionalSetting?.reductionConverged != true, "\(a)") } catch let error as CIFImportError { guard case .invalidStructure(let messages) = error else { Issue.record("\(error)"); continue } #expect(!messages.isEmpty) } } - let long = try CIFImport.read(try Self.fluorapatite(a: "1e12")) + let long = try CIFImport.read(try Self.fluorapatite(a: "1e12"), policy: Self.anyMetric) #expect(long.structure.conventionalSetting?.reductionConverged == false) #expect(long.structure.conventionalSetting?.bravais == .aP) } diff --git a/docs/open-items.md b/docs/open-items.md index 681b860..e1304b3 100644 --- a/docs/open-items.md +++ b/docs/open-items.md @@ -28,8 +28,11 @@ A plain list, worst first. Each line: the item, the cause where it is known, wha is not reproduced here: within 2.9 degrees of a template the nearest-bank gap is at most 1.6 degrees at 600 axes; a pattern between templates in a sparse corner of the zone is untested. Metal is not faster than all CPU cores up to 1 024 patterns at 600 axes; 16 384 patterns and 2 400 axes are not timed yet. -- **CIF symmetry.** Still unchecked: a group named by Hall symbol only, and a partial list whose count equals the primitive - group's order but whose operations are the wrong ones (a count cannot see that). +- **CIF symmetry.** A Hall symbol is read and a listed operation list is checked for its count, the cell metric, closure and + the IT number's crystal class. Still unchecked: a closed list of the right class and count with the wrong translations + (P4/m listed for P4_2/m, or another origin) when the file states no Hall symbol, since the kit has no table from a + number or Hermann-Mauguin symbol to operations; and a full loop that disagrees with the Hall symbol beside it (the loop + is used, as pymatgen does). - **Beam centre for a blocked beam.** `PatternCentre.find` refuses a pattern whose beam is blocked; Friedel-pair symmetry would find it. - **Ring fit.** `fitRing` at R 600 px on 2048² takes tens of seconds (a coarse-then-fine annulus, or Metal). A one-ring profile diff --git a/docs/parity.md b/docs/parity.md index b0e006d..d443aa4 100644 --- a/docs/parity.md +++ b/docs/parity.md @@ -94,7 +94,7 @@ and are counted apart. | P33 | orix 0.15.0 `Vector3d.in_fundamental_sector` and Laue groups in the kit frame, 12 class/setting entries, 3 765 poles, 1 500 probe poles per class | `tools/pins/orix/direction-pins.py` -> `orix-direction-pins.json` | `OrixDirectionTests` | orbit membership of the reduced pole against orix's folded pole 1e-5 absolute (was 1e-9; measured 1.1e-15), invariance over the orbit (the kit's own) 1e-9 (measured 9e-16); sampled poles in the zone and pairwise inequivalent; covering radii recorded in `docs/orientation-symmetry.md`. No kit change | | P34 | py4DSTEM f050d207 `Crystal.symmetry_reduce_directions` on real `Crystal`s: 57 centrosymmetric space groups across the 11 Laue classes and both -3m settings, pymatgen 2025.1.9 (the py4DSTEM venv's) operator order, `orientation_plan('auto')` sectors, 151 seeded and designed matrices each | `tools/pins/orientation-symmetry/family-real-pins.py` (py4DSTEM venv) -> `py4dstem-family-real-pins.json`, `PymatgenOperatorTable.swift` | `Py4DSTEMRealFamilyTests` | family entries 1e-7 absolute (was 1e-12; measured 4.4e-16) on 8 607 matrices; `.sortedFractional` (the P28 harness) differs on 139 and 136 of 151 for 2/m and -31m (recorded); wall columns not compared | | P35 | spglib 2.8.0 `get_spacegroup_type` over all 530 Hall settings: every Hermann-Mauguin spelling (short, full, unspaced, alternative settings; 1 048 symbols); pymatgen's primitive C2/m cell with beta = 90 (the fixture records `pymatgen` 2026.9.24, the metapackage; the code that built it is pymatgen-core 2026.10.16, the one on disk in `References/python/orix` and `py4dstem`; regenerated on 2026-10-21, the file is byte-identical) and spglib's operations in that cell | `tools/pins/cif-symmetry/pins.py` -> `Tests/DiffractoCoreTests/Fixtures/cif-symmetry-pins.json` | `CIFSymmetryCompletenessTests` | point-group order x centring equals `CIFImport.spaceGroupOrder` exactly for all 1 048; the primitive cell imports with its atom count (the rows it feeds: sections 1.6 and 1.3; the 0.9.0 numerics are in 2.3 and 2.4) | -| P37 | spglib 2.8.0 `get_symmetry_from_database` over all 530 Hall settings (7 388 operations, centring included) with `get_spacegroup_type(...).hall_symbol`; six planted CIFs that name their group by Hall symbol alone, with the atom count spglib's operations give and the count pymatgen-core 2026.10.16 `CifParser` builds (it reads no Hall symbol: P1 with a warning when there is no loop, the partial loop as given when there is one) | `tools/pins/cif-symmetry/hall-pins.py` -> `Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json` | `HallSymbolTests` | operation sets exact (rotations, translations in twelfths); atom counts exact | +| P37 | spglib 2.8.0 `get_symmetry_from_database` over all 530 Hall settings (7 388 operations, centring included) with `get_spacegroup_type(...).hall_symbol`; six planted CIFs that name their group by Hall symbol alone, with the atom count spglib's operations give and the count pymatgen-core 2026.10.16 `CifParser` builds (it reads no Hall symbol: P1 with a warning when there is no loop, the partial loop as given when there is one) | `tools/pins/cif-symmetry/hall-pins.py` -> `Tests/DiffractoCoreTests/Fixtures/hall-symbol-pins.json` | `HallSymbolTests`; the same 530 groups pin the crystal class read from the rotations against the IT number, and the planted wrong lists of `OperationListCheckTests` (another basis, not closed, another class) | operation sets exact (rotations, translations in twelfths); atom counts and classes exact | pyxem, diffsims and orix are **not pinned clones** here; py4DSTEM is held as its scattering table file (P5) and, for the vector matching and phase mapping of DiffractoOrientation, as a pinned f050d207 environment the pins run (P14, P18). The remaining unexecuted Python APIs below are a checklist, not an additional parity claim. P18 byte-checks the installed crystal.py, crystal_ACOM.py, crystal_viz.py and utils.py against the pinned clone before execution. @@ -178,7 +178,7 @@ matching and phase mapping of DiffractoOrientation, as a pinned f050d207 environ | Python function or option group | DiffractoKit symbol | State | Plan | Upstream tolerance (test file) | How checked | |---|---|---|---|---|---| | `CifParser.from_str(...).parse_structures()` | `CIFImport.read(_:fileBaseName:)` -> `CIFDocument.structure` | **partly** | study | tests not shipped; function arguments `occupancy_tolerance=1.0`, `site_tolerance=1e-4`, `frac_tolerance=1e-4`, `comp_tol=0.01` | P2 on 19 structures: cell, expanded sites, operations equal. Differences by design: the kit reads the subset that defines a structure (cell, atom-site loop, operation loop), refuses what it cannot expand safely (named errors, `CIFImportError`), merges images within the written precision and 0.10 A (pymatgen: `site_tolerance` 1e-4; the kit is looser by design) and detects the symmetry from the expanded cell; no file is read from disk (the caller passes text) | -| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables) | +| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables). A listed list must also map the cell onto itself, be closed and have the IT number's crystal class (`CIFImportError.inconsistentSymmetryOperations`); pymatgen checks none of these | | `CifParser(filename)`, `CifFile.from_file`, `CifBlock` | none | not held | not planned (`CIFImport` takes text; the caller reads files) | tests not shipped; assert_allclose defaults | | | `CifParser.get_symops` / `SymmOp.from_xyz_str`, `as_xyz_str` | `SymmetryOperation(xyz:)`, `xyzString` | **partly** | study | tests not shipped; assert_allclose defaults | P2 builds the pinned operations from pymatgen's strings; the grammar is mac4DSTEM 7d6fdbd1's with a refusal of singular rotations added (`SymmetryOperationTests`); `xyzString` is not compared with `as_xyz_str` | | `MPRester` summary documents (`structure`, `symmetry`) as a source of structures | `MaterialsProjectImport` (`decode`, `structure(from:)`, `check(_:against:)`), `MaterialsProjectDocument` | **partly** | useful | tests not shipped; assert_allclose defaults | P20, P30: the conventional cell built from the committed MP-shaped inputs equals pymatgen's `SpacegroupAnalyzer` conventional cell (volume 1e-7); the request builder is not run against the service. MP and ICSD database access beyond the request builder is not planned | From f05a8baabeefad006040f5a92f83d218b1d25afb Mon Sep 17 00:00:00 2001 From: Paullo9 Date: Sat, 31 Oct 2026 12:06:37 +0100 Subject: [PATCH 3/5] docs: name the pymatgen deviation of the operation-list refusal docs/parity.md gains a DEVIATION in the CIF symmetry row: pymatgen-core 2026.10.16 CifParser admits an operation list that does not map the cell onto itself, is not closed or has another crystal class than the IT number, and expands it as given; the kit refuses it and names the cause in words. A full loop that disagrees with the Hall symbol beside it is used, as pymatgen does. A test checks that every SymmetryListProblem says its cause in words (not mapping the cell onto itself, not a space group, the two crystal classes or none of the 32) and that the error an app shows carries that sentence whole. Done: refusals named in words and the deviation recorded. Next: a warning on the result when a full loop disagrees with the Hall symbol (needs a warnings field on CIFDocument, filed separately). Co-Authored-By: Claude Opus 5.5 --- .../OperationListCheckTests.swift | 17 +++++++++++++++++ docs/parity.md | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Tests/DiffractoCoreTests/OperationListCheckTests.swift b/Tests/DiffractoCoreTests/OperationListCheckTests.swift index 4cfd667..52ee5c8 100644 --- a/Tests/DiffractoCoreTests/OperationListCheckTests.swift +++ b/Tests/DiffractoCoreTests/OperationListCheckTests.swift @@ -150,4 +150,21 @@ struct OperationListCheckTests { #expect(CIFImportError.inconsistentSymmetryOperations(.notACellSymmetry(operation: "-x,y,z")).description .contains("refused")) } + + /// Every refusal names its cause in words, not only the operations, and the error an app shows (its + /// `localizedDescription`) carries that sentence whole. + @Test func everyRefusalNamesItsCauseInWords() { + let causes: [(SymmetryListProblem, String)] = [ + (.notACellSymmetry(operation: "-x,y,z"), "does not map the cell onto itself"), + (.notClosed(first: "-y,x,z", second: "x,-y,z", product: "y,x,z"), "is not a space group"), + (.wrongCrystalClass(spaceGroupNumber: 83, listed: "mmm", required: "4/m"), "crystal class mmm"), + (.wrongCrystalClass(spaceGroupNumber: 83, listed: nil, required: "4/m"), "none of the 32 point groups"), + ] + for (problem, cause) in causes { + #expect(problem.description.contains(cause), "\(problem)") + let error: any Error = CIFImportError.inconsistentSymmetryOperations(problem) + #expect(error.localizedDescription.contains(problem.description), "\(problem)") + #expect(error.localizedDescription.contains("cannot be its space group"), "\(problem)") + } + } } diff --git a/docs/parity.md b/docs/parity.md index d443aa4..ee04ce3 100644 --- a/docs/parity.md +++ b/docs/parity.md @@ -178,7 +178,7 @@ matching and phase mapping of DiffractoOrientation, as a pinned f050d207 environ | Python function or option group | DiffractoKit symbol | State | Plan | Upstream tolerance (test file) | How checked | |---|---|---|---|---|---| | `CifParser.from_str(...).parse_structures()` | `CIFImport.read(_:fileBaseName:)` -> `CIFDocument.structure` | **partly** | study | tests not shipped; function arguments `occupancy_tolerance=1.0`, `site_tolerance=1e-4`, `frac_tolerance=1e-4`, `comp_tol=0.01` | P2 on 19 structures: cell, expanded sites, operations equal. Differences by design: the kit reads the subset that defines a structure (cell, atom-site loop, operation loop), refuses what it cannot expand safely (named errors, `CIFImportError`), merges images within the written precision and 0.10 A (pymatgen: `site_tolerance` 1e-4; the kit is looser by design) and detects the symmetry from the expanded cell; no file is read from disk (the caller passes text) | -| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables). A listed list must also map the cell onto itself, be closed and have the IT number's crystal class (`CIFImportError.inconsistentSymmetryOperations`); pymatgen checks none of these | +| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables). A listed list must also map the cell onto itself, be closed and have the IT number's crystal class (`CIFImportError.inconsistentSymmetryOperations`); pymatgen checks none of these. **DEVIATION**: pymatgen-core 2026.10.16 `CifParser` admits a listed operation list that does not map the cell onto itself, is not closed, or has another crystal class than the IT number, and expands the atom sites with it as given; the kit refuses such a file, and the error names the cause in words (`SymmetryListProblem`: the operation that does not map the cell onto itself, the product the list lacks, or the two crystal classes). A full loop that disagrees with the Hall symbol beside it is used, as pymatgen does | | `CifParser(filename)`, `CifFile.from_file`, `CifBlock` | none | not held | not planned (`CIFImport` takes text; the caller reads files) | tests not shipped; assert_allclose defaults | | | `CifParser.get_symops` / `SymmOp.from_xyz_str`, `as_xyz_str` | `SymmetryOperation(xyz:)`, `xyzString` | **partly** | study | tests not shipped; assert_allclose defaults | P2 builds the pinned operations from pymatgen's strings; the grammar is mac4DSTEM 7d6fdbd1's with a refusal of singular rotations added (`SymmetryOperationTests`); `xyzString` is not compared with `as_xyz_str` | | `MPRester` summary documents (`structure`, `symmetry`) as a source of structures | `MaterialsProjectImport` (`decode`, `structure(from:)`, `check(_:against:)`), `MaterialsProjectDocument` | **partly** | useful | tests not shipped; assert_allclose defaults | P20, P30: the conventional cell built from the committed MP-shaped inputs equals pymatgen's `SpacegroupAnalyzer` conventional cell (volume 1e-7); the request builder is not run against the service. MP and ICSD database access beyond the request builder is not planned | From 5a8853afe57e1f2f592a9ba7dca6aee124c41b72 Mon Sep 17 00:00:00 2001 From: Paullo9 Date: Sat, 31 Oct 2026 14:00:25 +0100 Subject: [PATCH 4/5] feat: warn when a full operation loop disagrees with the Hall symbol beside it CIFDocument.warnings (CIFImportWarning.operationLoopIsNotTheHallGroup) names the Hall symbol and both orders when a listed loop is not the Hall group modulo lattice translations. The loop is still used, as pymatgen-core 2026.10.16 CifParser uses it. HallLoopWarningTests: a P4/mmm loop beside -P 2 2 warns, beside -P 4 2 or no Hall symbol it does not. Stacked on issue-9-symop-checks. Not pushed: the work was paused before review. Co-Authored-By: Claude Opus 5.5 --- Sources/DiffractoCore/CIFImport.swift | 39 +++++++++- .../DiffractoCore.docc/DiffractoCore.md | 1 + .../HallLoopWarningTests.swift | 73 +++++++++++++++++++ docs/parity.md | 2 +- 4 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 Tests/DiffractoCoreTests/HallLoopWarningTests.swift diff --git a/Sources/DiffractoCore/CIFImport.swift b/Sources/DiffractoCore/CIFImport.swift index 90f4e4e..28fe784 100644 --- a/Sources/DiffractoCore/CIFImport.swift +++ b/Sources/DiffractoCore/CIFImport.swift @@ -107,6 +107,22 @@ extension CIFImportError: LocalizedError { public var errorDescription: String? { description } } +/// Something the import noticed and read past: the file is read, and the structure is the one described, but an app +/// should show the warning beside it (`CIFDocument.warnings`). +public enum CIFImportWarning: Sendable, Equatable, CustomStringConvertible { + /// The file lists a full operation loop and states a Hall symbol whose group is another one (compared modulo lattice + /// translations). The loop was used, as pymatgen-core 2026.10.16 `CifParser` uses it; the Hall symbol was not. + case operationLoopIsNotTheHallGroup(hallSymbol: String, loopOrder: Int, hallOrder: Int) + + public var description: String { + switch self { + case let .operationLoopIsNotTheHallGroup(hallSymbol, loopOrder, hallOrder): + return "The operation loop (\(loopOrder) operations) is not the group of the Hall symbol \(hallSymbol) " + + "(\(hallOrder) operations); the loop was used." + } + } +} + /// What a CIF read yields: the structure and what the file said about itself. public struct CIFDocument: Sendable, Equatable { public let structure: CrystalStructure @@ -125,6 +141,8 @@ public struct CIFDocument: Sendable, Equatable { /// Whether the file carried expanding operations (`structure.fileOperations`): a symmetry-operation loop, or, with no /// loop, a Hall symbol read to its group. The structure's operations are detected from the expanded cell either way. public let hadSymmetryOperations: Bool + /// What the import read past (``CIFImportWarning``), in the order found; empty for a file with nothing to report. + public let warnings: [CIFImportWarning] } public enum CIFImport { @@ -214,7 +232,8 @@ public enum CIFImport { declaredSpaceGroupNumber: parsed.spaceGroupNumber, declaredHallSymbol: parsed.hallSymbol, coarsestHalfStep: parsed.coarsestHalfStep, - hadSymmetryOperations: parsed.operations != nil) + hadSymmetryOperations: parsed.operations != nil, + warnings: parsed.warnings) } /// The name a structure imports under: the CIF's `data_` block name, unless it says nothing — empty, or the @@ -240,6 +259,7 @@ public enum CIFImport { var spaceGroupNumber: Int? var spaceGroupSymbol: String? var hallSymbol: String? + var warnings: [CIFImportWarning] } /// One asymmetric-unit site plus how precisely each of its coordinates was written: `halfStep` is the half-width @@ -420,6 +440,21 @@ public enum CIFImport { // A loop, even one holding only the identity, is what the file lists and wins over the symbol (as in pymatgen). let expandsWithHall = !haveSymmetryLoop && (hallOperations?.count ?? 0) > 1 if expandsWithHall, let hallOperations { ops = hallOperations } + // A loop beside a readable Hall symbol of another group is used all the same (pymatgen reads no Hall symbol and + // uses the loop), but the reader is told. Equal groups: the same order and every listed operation in the Hall + // group, translations mod 1 to 1e-3 (the finest genuine translation is 1/12; a written 0.3333 is 1/3). + var warnings: [CIFImportWarning] = [] + if fileListsOperations, let hallSymbol, let hallOperations { + let loopOrder = SymmetryOperation.distinctCount(ops) + let hallOrder = SymmetryOperation.distinctCount(hallOperations) + let sameGroup = loopOrder == hallOrder && ops.allSatisfy { op in + hallOperations.contains { $0.isEquivalent(to: op, translationTolerance: 1e-3) } + } + if !sameGroup { + warnings.append(.operationLoopIsNotTheHallGroup(hallSymbol: hallSymbol, loopOrder: loopOrder, + hallOrder: hallOrder)) + } + } let sites: [AtomSite] let operations: [SymmetryOperation]? @@ -493,7 +528,7 @@ public enum CIFImport { a: a, b: b, c: c, alpha: alpha, beta: beta, gamma: gamma, sites: sites, operations: operations, coarsestHalfStep: coarsestHalfStep, spaceGroupNumber: spaceGroupNumber, spaceGroupSymbol: declaredHermannMauguin(cellValues), - hallSymbol: hallSymbol) + hallSymbol: hallSymbol, warnings: warnings) } // MARK: - Tokenizer diff --git a/Sources/DiffractoCore/DiffractoCore.docc/DiffractoCore.md b/Sources/DiffractoCore/DiffractoCore.docc/DiffractoCore.md index e80896c..8023e65 100644 --- a/Sources/DiffractoCore/DiffractoCore.docc/DiffractoCore.md +++ b/Sources/DiffractoCore/DiffractoCore.docc/DiffractoCore.md @@ -26,6 +26,7 @@ It uses `Foundation` and `simd` only. Start with . - ``CIFImport`` - ``CIFDocument`` - ``CIFImportError`` +- ``CIFImportWarning`` ### Cells, sites and elements diff --git a/Tests/DiffractoCoreTests/HallLoopWarningTests.swift b/Tests/DiffractoCoreTests/HallLoopWarningTests.swift new file mode 100644 index 0000000..d9a6a7d --- /dev/null +++ b/Tests/DiffractoCoreTests/HallLoopWarningTests.swift @@ -0,0 +1,73 @@ +// +// HallLoopWarningTests.swift +// A CIF that lists a full operation loop and also states a Hall symbol of another group: the loop is used, as +// pymatgen-core 2026.10.16 `CifParser` uses it (it reads no Hall symbol), and the document carries a warning that names +// the symbol and the two orders. The groups are spglib 2.8.0's (`hall-symbol-pins.json`). +// + +import DiffractoKitTestSupport +import Foundation +import Testing +@testable import DiffractoCore + +struct HallLoopWarningTests { + static func cif(hall: String?, ops: [String]) -> String { + var s = "data_t\n_symmetry_Int_Tables_number 123\n" + if let hall { s += "_space_group_name_Hall '\(hall)'\n" } + for (tag, v) in zip(["length_a", "length_b", "length_c", "angle_alpha", "angle_beta", "angle_gamma"], + [10.0, 10.0, 12.0, 90, 90, 90]) { + s += "_cell_\(tag) \(v)\n" + } + s += "loop_\n_symmetry_equiv_pos_as_xyz\n" + ops.map { "'\($0)'" }.joined(separator: "\n") + "\n" + s += "loop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\n" + s += "Si1 Si 0.1 0.2 0.3\n" + return s + } + + /// A P4/mmm loop beside the Hall symbol of mmm (-P 2 2): the 16 images of a general site are read from the loop, and + /// one warning names the symbol and the orders 16 and 8. RED UNDER: `CIFDocument` had no warnings. + @Test func aLoopOfAnotherGroupThanTheHallSymbolIsUsedWithAWarning() throws { + let loop = try OperationListCheckTests.group("-P 4 2").map(\.xyzString) + #expect(loop.count == 16) + let document = try CIFImport.read(Self.cif(hall: "-P 2 2", ops: loop)) + #expect(document.structure.sites.count == 16) + #expect(document.warnings == [.operationLoopIsNotTheHallGroup(hallSymbol: "-P 2 2", loopOrder: 16, hallOrder: 8)]) + let text = try #require(document.warnings.first).description + #expect(text.contains("-P 2 2") && text.contains("16") && text.contains("8") && text.contains("loop was used")) + } + + /// The same loop beside its own Hall symbol (-P 4 2), and beside none: no warning, the same 16 sites. + @Test func aLoopOfTheHallGroupOrWithoutAHallSymbolHasNoWarning() throws { + let loop = try OperationListCheckTests.group("-P 4 2").map(\.xyzString) + for hall in ["-P 4 2", nil] as [String?] { + let document = try CIFImport.read(Self.cif(hall: hall, ops: loop)) + #expect(document.structure.sites.count == 16) + #expect(document.warnings.isEmpty, "\(hall ?? "no Hall symbol")") + } + } + + /// The loop written in reverse order, with every translation moved by a lattice vector, is still the Hall group: the + /// comparison is of sets, modulo lattice translations. + @Test func theComparisonIgnoresOrderAndLatticeTranslations() throws { + let ops = try OperationListCheckTests.group("-P 4 2") + let shifted = ops.reversed().map { op in + SymmetryOperation(rotation: op.rotation, translation: op.translation + SIMD3(1, 0, -1)).xyzString + } + let document = try CIFImport.read(Self.cif(hall: "-P 4 2", ops: shifted)) + #expect(document.warnings.isEmpty) + } + + /// Every file read without a Hall symbol, or with only a Hall symbol, has no warning. + @Test func aHallOnlyFileHasNoWarning() throws { + var s = "data_t\n_space_group_name_Hall '-P 4 2'\n" + for (tag, v) in zip(["length_a", "length_b", "length_c", "angle_alpha", "angle_beta", "angle_gamma"], + [10.0, 10.0, 12.0, 90, 90, 90]) { + s += "_cell_\(tag) \(v)\n" + } + s += "loop_\n_atom_site_label\n_atom_site_type_symbol\n_atom_site_fract_x\n_atom_site_fract_y\n_atom_site_fract_z\n" + s += "Si1 Si 0.1 0.2 0.3\n" + let document = try CIFImport.read(s) + #expect(document.structure.sites.count == 16) + #expect(document.warnings.isEmpty) + } +} diff --git a/docs/parity.md b/docs/parity.md index ee04ce3..ecaaf30 100644 --- a/docs/parity.md +++ b/docs/parity.md @@ -178,7 +178,7 @@ matching and phase mapping of DiffractoOrientation, as a pinned f050d207 environ | Python function or option group | DiffractoKit symbol | State | Plan | Upstream tolerance (test file) | How checked | |---|---|---|---|---|---| | `CifParser.from_str(...).parse_structures()` | `CIFImport.read(_:fileBaseName:)` -> `CIFDocument.structure` | **partly** | study | tests not shipped; function arguments `occupancy_tolerance=1.0`, `site_tolerance=1e-4`, `frac_tolerance=1e-4`, `comp_tol=0.01` | P2 on 19 structures: cell, expanded sites, operations equal. Differences by design: the kit reads the subset that defines a structure (cell, atom-site loop, operation loop), refuses what it cannot expand safely (named errors, `CIFImportError`), merges images within the written precision and 0.10 A (pymatgen: `site_tolerance` 1e-4; the kit is looser by design) and detects the symmetry from the expanded cell; no file is read from disk (the caller passes text) | -| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables). A listed list must also map the cell onto itself, be closed and have the IT number's crystal class (`CIFImportError.inconsistentSymmetryOperations`); pymatgen checks none of these. **DEVIATION**: pymatgen-core 2026.10.16 `CifParser` admits a listed operation list that does not map the cell onto itself, is not closed, or has another crystal class than the IT number, and expands the atom sites with it as given; the kit refuses such a file, and the error names the cause in words (`SymmetryListProblem`: the operation that does not map the cell onto itself, the product the list lacks, or the two crystal classes). A full loop that disagrees with the Hall symbol beside it is used, as pymatgen does | +| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables). A listed list must also map the cell onto itself, be closed and have the IT number's crystal class (`CIFImportError.inconsistentSymmetryOperations`); pymatgen checks none of these. **DEVIATION**: pymatgen-core 2026.10.16 `CifParser` admits a listed operation list that does not map the cell onto itself, is not closed, or has another crystal class than the IT number, and expands the atom sites with it as given; the kit refuses such a file, and the error names the cause in words (`SymmetryListProblem`: the operation that does not map the cell onto itself, the product the list lacks, or the two crystal classes). A full loop that disagrees with the Hall symbol beside it is used, as pymatgen does; pymatgen says nothing, the kit adds `CIFImportWarning.operationLoopIsNotTheHallGroup` (the symbol and both orders) to `CIFDocument.warnings` (`HallLoopWarningTests`: a P4/mmm loop beside -P 2 2 warns, beside -P 4 2 does not) | | `CifParser(filename)`, `CifFile.from_file`, `CifBlock` | none | not held | not planned (`CIFImport` takes text; the caller reads files) | tests not shipped; assert_allclose defaults | | | `CifParser.get_symops` / `SymmOp.from_xyz_str`, `as_xyz_str` | `SymmetryOperation(xyz:)`, `xyzString` | **partly** | study | tests not shipped; assert_allclose defaults | P2 builds the pinned operations from pymatgen's strings; the grammar is mac4DSTEM 7d6fdbd1's with a refusal of singular rotations added (`SymmetryOperationTests`); `xyzString` is not compared with `as_xyz_str` | | `MPRester` summary documents (`structure`, `symmetry`) as a source of structures | `MaterialsProjectImport` (`decode`, `structure(from:)`, `check(_:against:)`), `MaterialsProjectDocument` | **partly** | useful | tests not shipped; assert_allclose defaults | P20, P30: the conventional cell built from the committed MP-shaped inputs equals pymatgen's `SpacegroupAnalyzer` conventional cell (volume 1e-7); the request builder is not run against the service. MP and ICSD database access beyond the request builder is not planned | From 75b92072f0fb4fc2ba556a48cfed4a64c17f92ae Mon Sep 17 00:00:00 2001 From: Paullo9 Date: Sat, 31 Oct 2026 14:12:33 +0100 Subject: [PATCH 5/5] test: the Hall loop warning compares operations, not only orders A P4/mmm loop beside the Hall symbol of P4/mcc (-P 4 2c, also 16 operations) now warns in a test, so dropping the operation comparison and keeping only the order check turns the suite red (checked by that mutation). A Hall symbol that cannot be read beside a valid loop reads with no warning and no error. The warning and docs/parity.md say a loop that passes the completeness checks, not a full loop. Done: review findings on the warning fixed. Next: open the PR after #49. Co-Authored-By: Claude Opus 5.5 --- Sources/DiffractoCore/CIFImport.swift | 4 ++-- .../HallLoopWarningTests.swift | 18 ++++++++++++++++++ docs/parity.md | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Sources/DiffractoCore/CIFImport.swift b/Sources/DiffractoCore/CIFImport.swift index 28fe784..5023847 100644 --- a/Sources/DiffractoCore/CIFImport.swift +++ b/Sources/DiffractoCore/CIFImport.swift @@ -110,8 +110,8 @@ extension CIFImportError: LocalizedError { /// Something the import noticed and read past: the file is read, and the structure is the one described, but an app /// should show the warning beside it (`CIFDocument.warnings`). public enum CIFImportWarning: Sendable, Equatable, CustomStringConvertible { - /// The file lists a full operation loop and states a Hall symbol whose group is another one (compared modulo lattice - /// translations). The loop was used, as pymatgen-core 2026.10.16 `CifParser` uses it; the Hall symbol was not. + /// The file lists an operation loop (one that passes the completeness checks) and states a Hall symbol whose group + /// is another one (compared modulo lattice translations). The loop was used, as pymatgen-core 2026.10.16 `CifParser` uses it; the Hall symbol was not. case operationLoopIsNotTheHallGroup(hallSymbol: String, loopOrder: Int, hallOrder: Int) public var description: String { diff --git a/Tests/DiffractoCoreTests/HallLoopWarningTests.swift b/Tests/DiffractoCoreTests/HallLoopWarningTests.swift index d9a6a7d..7be795c 100644 --- a/Tests/DiffractoCoreTests/HallLoopWarningTests.swift +++ b/Tests/DiffractoCoreTests/HallLoopWarningTests.swift @@ -36,6 +36,24 @@ struct HallLoopWarningTests { #expect(text.contains("-P 2 2") && text.contains("16") && text.contains("8") && text.contains("loop was used")) } + /// Equal orders are not enough: a P4/mmm loop (16 operations) beside the Hall symbol of P4/mcc (-P 4 2c, also 16 + /// operations, the same crystal class) warns, because the c-glide operations are not in the loop. + @Test func aLoopOfTheSameOrderButAnotherGroupWarns() throws { + let loop = try OperationListCheckTests.group("-P 4 2").map(\.xyzString) + #expect(try OperationListCheckTests.group("-P 4 2c").count == 16) + let document = try CIFImport.read(Self.cif(hall: "-P 4 2c", ops: loop)) + #expect(document.structure.sites.count == 16) + #expect(document.warnings == [.operationLoopIsNotTheHallGroup(hallSymbol: "-P 4 2c", loopOrder: 16, hallOrder: 16)]) + } + + /// A Hall symbol that cannot be read beside a valid loop: the loop is used, nothing is thrown and nothing is warned. + @Test func anUnreadableHallSymbolBesideALoopHasNoWarning() throws { + let loop = try OperationListCheckTests.group("-P 4 2").map(\.xyzString) + let document = try CIFImport.read(Self.cif(hall: "Q 9 9", ops: loop)) + #expect(document.structure.sites.count == 16) + #expect(document.warnings.isEmpty) + } + /// The same loop beside its own Hall symbol (-P 4 2), and beside none: no warning, the same 16 sites. @Test func aLoopOfTheHallGroupOrWithoutAHallSymbolHasNoWarning() throws { let loop = try OperationListCheckTests.group("-P 4 2").map(\.xyzString) diff --git a/docs/parity.md b/docs/parity.md index ecaaf30..273e1d8 100644 --- a/docs/parity.md +++ b/docs/parity.md @@ -178,7 +178,7 @@ matching and phase mapping of DiffractoOrientation, as a pinned f050d207 environ | Python function or option group | DiffractoKit symbol | State | Plan | Upstream tolerance (test file) | How checked | |---|---|---|---|---|---| | `CifParser.from_str(...).parse_structures()` | `CIFImport.read(_:fileBaseName:)` -> `CIFDocument.structure` | **partly** | study | tests not shipped; function arguments `occupancy_tolerance=1.0`, `site_tolerance=1e-4`, `frac_tolerance=1e-4`, `comp_tol=0.01` | P2 on 19 structures: cell, expanded sites, operations equal. Differences by design: the kit reads the subset that defines a structure (cell, atom-site loop, operation loop), refuses what it cannot expand safely (named errors, `CIFImportError`), merges images within the written precision and 0.10 A (pymatgen: `site_tolerance` 1e-4; the kit is looser by design) and detects the symmetry from the expanded cell; no file is read from disk (the caller passes text) | -| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables). A listed list must also map the cell onto itself, be closed and have the IT number's crystal class (`CIFImportError.inconsistentSymmetryOperations`); pymatgen checks none of these. **DEVIATION**: pymatgen-core 2026.10.16 `CifParser` admits a listed operation list that does not map the cell onto itself, is not closed, or has another crystal class than the IT number, and expands the atom sites with it as given; the kit refuses such a file, and the error names the cause in words (`SymmetryListProblem`: the operation that does not map the cell onto itself, the product the list lacks, or the two crystal classes). A full loop that disagrees with the Hall symbol beside it is used, as pymatgen does; pymatgen says nothing, the kit adds `CIFImportWarning.operationLoopIsNotTheHallGroup` (the symbol and both orders) to `CIFDocument.warnings` (`HallLoopWarningTests`: a P4/mmm loop beside -P 2 2 warns, beside -P 4 2 does not) | +| symmetry of a CIF that names a group but lists no operations (`get_symops` falling back to `SpaceGroup`), and a group named by Hermann-Mauguin symbol alone | `CIFDocument.declaredSpaceGroupSymbol`, `declaredSpaceGroupNumber`, `declaredHallSymbol`, `CIFImport.spaceGroupOrder`; `hadSymmetryOperations` | **partly** | study | tests not shipped; assert_allclose defaults | the completeness check works from the IT number, else the Hermann-Mauguin symbol (P35), else the Hall symbol (P37). A Hall symbol with no loop is expanded with its own group (P37: the spglib atom count; pymatgen builds P1 there); a number or Hermann-Mauguin symbol with no loop is refused (no tables). A listed list must also map the cell onto itself, be closed and have the IT number's crystal class (`CIFImportError.inconsistentSymmetryOperations`); pymatgen checks none of these. **DEVIATION**: pymatgen-core 2026.10.16 `CifParser` admits a listed operation list that does not map the cell onto itself, is not closed, or has another crystal class than the IT number, and expands the atom sites with it as given; the kit refuses such a file, and the error names the cause in words (`SymmetryListProblem`: the operation that does not map the cell onto itself, the product the list lacks, or the two crystal classes). A loop that passes those checks and disagrees with the Hall symbol beside it is used, as pymatgen does; pymatgen says nothing, the kit adds `CIFImportWarning.operationLoopIsNotTheHallGroup` (the symbol and both orders) to `CIFDocument.warnings` (`HallLoopWarningTests`: a P4/mmm loop beside -P 2 2 or -P 4 2c warns, beside -P 4 2 or an unreadable symbol does not) | | `CifParser(filename)`, `CifFile.from_file`, `CifBlock` | none | not held | not planned (`CIFImport` takes text; the caller reads files) | tests not shipped; assert_allclose defaults | | | `CifParser.get_symops` / `SymmOp.from_xyz_str`, `as_xyz_str` | `SymmetryOperation(xyz:)`, `xyzString` | **partly** | study | tests not shipped; assert_allclose defaults | P2 builds the pinned operations from pymatgen's strings; the grammar is mac4DSTEM 7d6fdbd1's with a refusal of singular rotations added (`SymmetryOperationTests`); `xyzString` is not compared with `as_xyz_str` | | `MPRester` summary documents (`structure`, `symmetry`) as a source of structures | `MaterialsProjectImport` (`decode`, `structure(from:)`, `check(_:against:)`), `MaterialsProjectDocument` | **partly** | useful | tests not shipped; assert_allclose defaults | P20, P30: the conventional cell built from the committed MP-shaped inputs equals pymatgen's `SpacegroupAnalyzer` conventional cell (volume 1e-7); the request builder is not run against the service. MP and ICSD database access beyond the request builder is not planned |