Changeset 7474:3b13ea60370c
- Timestamp:
- 12/01/07 16:43:40 (6 years ago)
- Branch:
- default
- Location:
- sage/modules
- Files:
-
- 3 edited
-
free_module.py (modified) (4 diffs)
-
matrix_morphism.py (modified) (1 diff)
-
vector_rational_dense.pyx (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
sage/modules/free_module.py
r7355 r7474 2336 2336 """ 2337 2337 return FreeModule_submodule_field(self.ambient_vector_space(),[], check=False) 2338 2339 def quotient(self,sub): 2338 2339 # This has to wait until we have non-abstract quotients. 2340 def __div__(self, sub, check=True): 2341 """ 2342 Return the quotient of self by the given subspace sub. 2343 2344 This just calls self.quotient(sub, check) 2345 2346 EXAMPLES: 2347 sage: V = RDF^3; W = V.span([[1,0,-1], [1,-1,0]]) 2348 sage: Q = V/W; Q 2349 Vector space quotient V/W of dimension 1 over Real Double Field where 2350 V: Vector space of dimension 3 over Real Double Field 2351 W: Vector space of degree 3 and dimension 2 over Real Double Field 2352 Basis matrix: 2353 [ 1.0 0.0 -1.0] 2354 [ 0.0 1.0 -1.0] 2355 sage: type(Q) 2356 <class 'sage.modules.quotient_module.FreeModule_ambient_field_quotient'> 2357 sage: V([1,2,3]) 2358 (1.0, 2.0, 3.0) 2359 sage: Q == V.quotient(W) 2360 True 2361 sage: Q(W.0) 2362 (0.0) 2363 """ 2364 return self.quotient(sub, check) 2365 2366 def quotient(self, sub, check=True): 2367 """ 2368 Return the quotient of self by the given subspace sub. 2369 2370 INPUT: 2371 sub -- a submodule of self, or something that can be turned into 2372 one via self.submodule(sub). 2373 check -- (default: True) whether or not to check that sub is 2374 a submodule. 2375 2376 EXAMPLES: 2377 sage: A = QQ^3; V = A.span([[1,2,3], [4,5,6]]) 2378 sage: Q = V.quotient( [V.0 + V.1] ); Q 2379 Vector space quotient V/W of dimension 1 over Rational Field where 2380 V: Vector space of degree 3 and dimension 2 over Rational Field 2381 Basis matrix: 2382 [ 1 0 -1] 2383 [ 0 1 2] 2384 W: Vector space of degree 3 and dimension 1 over Rational Field 2385 Basis matrix: 2386 [1 1 1] 2387 sage: Q(V.0 + V.1) 2388 (0) 2389 """ 2390 # Calling is_subspace may be way too slow and repeat work done below. 2391 # It will be very desirable to somehow do this step better. 2392 if check and (not is_FreeModule(sub) or not sub.is_subspace(self)): 2393 try: 2394 sub = self.subspace(sub) 2395 except (TypeError, ArithmeticError): 2396 raise ArithmeticError, "sub must be a subspace of self" 2397 A, L = self.__quotient_matrices(sub) 2398 import quotient_module 2399 return quotient_module.FreeModule_ambient_field_quotient(self, sub, A, L) 2400 2401 def __quotient_matrices(self, sub): 2340 2402 r""" 2341 Returns the quotient space of self modulo sub, together with a 2342 map sub must be a subspace of self. 2343 2344 EXAMPLES: 2345 sage: A=matrix(QQ,4,4,[0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0]) 2346 sage: V=(A^3).kernel() 2347 sage: W=A.kernel() 2348 sage: U,m=V.quotient(W) 2349 sage: [m(v) == 0 for v in W.gens()] 2403 This internal function is used by \code{self.quotient(...)}. 2404 2405 EXAMPLES: 2406 sage: V = QQ^3; W = V.span([[1,0,-1], [1,-1,0]]) 2407 sage: A, L = V._FreeModule_generic_field__quotient_matrices(W) 2408 sage: A 2409 [1/3] 2410 [1/3] 2411 [1/3] 2412 sage: L 2413 [1 1 1] 2414 2415 The quotient and lift maps are used to compute in the quotient 2416 and to lift: 2417 sage: Q = V/W 2418 sage: Q(W.0) 2419 (0) 2420 sage: Q.lift_map()(Q.0) 2421 (1, 1, 1) 2422 sage: Q(Q.lift_map()(Q.0)) 2423 (1) 2424 """ 2425 # 2. Find a basis C for a another submodule of self, so that 2426 # B + C is a basis for self. 2427 # 3. Then the quotient map is: 2428 # x |---> 'write in terms of basis for C and take the last m = #C-#B components. 2429 # 4. And a section of this map is: 2430 # x |---> corresponding linear combination of entries of last m entries 2431 # of the basis C. 2432 2433 # Step 1: Find bases for spaces 2434 B = sub.basis_matrix() 2435 S = self.basis_matrix() 2436 2437 # Step 2: Extend basis B to a basis for self. 2438 # 2439 # Compute a subspace of self with the property that each 2440 # element of M has dot product 0 with each element of sub. 2441 # This M is thus the orthogonal complement (with respect to 2442 # dot product) of the submodule sub inside self. 2443 # Then let C be a matrix with these rows. 2444 2445 C = B.transpose().restrict_domain(self).kernel().basis_matrix() 2446 C = C * S 2447 n = self.dimension() 2448 m = C.nrows() 2449 2450 # Now B and C together form a matrix whose rows are a basis for self. 2451 A = B.stack(C) 2452 2453 # Step 3: Compute quotient map 2454 # The quotient map is given by writing in terms of the above basis, 2455 # then taking the last #C columns 2456 2457 # Compute the matrix D "change of basis from S to A" 2458 # that writes each element of the basis 2459 # for self in terms of the basis of rows of A, i.e., 2460 # want to find D such that 2461 # D * A = S 2462 # where D is a square n x n matrix. 2463 # Our algorithm is to note that D is determined if we just 2464 # replace both A and S by the submatrix got from their pivot 2465 # columns. 2466 P = A.pivots() 2467 AA = A.matrix_from_columns(P) 2468 SS = S.matrix_from_columns(P) 2469 D = SS * AA**(-1) 2470 2471 # Compute the image of each basis vector for self under the 2472 # map "write an element of self in terms of the basis A" then 2473 # take the last n-m components. 2474 Q = D.matrix_from_columns(range(n - m, n)) 2475 2476 # Step 4. Section map 2477 # The lifting or section map 2478 Dinv = D**(-1) 2479 L = Dinv.matrix_from_rows(range(n - C.nrows(), n)) 2480 2481 return Q, L 2482 2483 def quotient_abstract(self, sub, check=True): 2484 r""" 2485 Returns an ambient free module isomorphic to the quotient 2486 space of self modulo sub, together with maps from self to the 2487 quotient, and a lifting map in the other direction. 2488 2489 Use \code{self.quotient(sub)} to obtain the quotient module 2490 as an object equipped with natural maps in both directions, 2491 and a canonical coercion. 2492 2493 INPUT: 2494 sub -- a submodule of self, or something that can be turned into 2495 one via self.submodule(sub). 2496 check -- (default: True) whether or not to check that sub is 2497 a submodule. 2498 2499 OUTPUT: 2500 U -- the quotient as an abstract *ambient* free module 2501 pi -- projection map to the quotient 2502 lift -- lifting map back from quotient 2503 2504 EXAMPLES: 2505 sage: V = GF(19)^3 2506 sage: W = V.span_of_basis([ [1,2,3], [1,0,1] ]) 2507 sage: U,pi,lift = V.quotient_abstract(W) 2508 sage: pi(V.2) 2509 (6) 2510 sage: pi(V.0) 2511 (13) 2512 sage: pi(V.0 + V.2) 2513 (0) 2514 2515 Another example involving a quotient of one subspace by another. 2516 sage: A = matrix(QQ,4,4,[0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0]) 2517 sage: V = (A^3).kernel() 2518 sage: W = A.kernel() 2519 sage: U, pi, lift = V.quotient_abstract(W) 2520 sage: [pi(v) == 0 for v in W.gens()] 2350 2521 [True] 2351 2352 TODO: 2353 * produce a convenient section map back from the quotient space 2354 * install appropriate coercions 2355 """ 2356 if not sub.is_subspace(self): 2357 raise ArithmeticError, "sub must be a subspace of self" 2358 M = sub.basis_matrix().transpose().restrict_domain(self).kernel().basis_matrix().transpose() 2359 quomap = self.hom(M) 2360 return quomap.codomain(),quomap 2361 2522 sage: [pi(lift(b)) == b for b in U.basis()] 2523 [True, True] 2524 """ 2525 # Calling is_subspace may be way too slow and repeat work done below. 2526 # It will be very desirable to somehow do this step better. 2527 if check and (not is_FreeModule(sub) or not sub.is_subspace(self)): 2528 try: 2529 sub = self.subspace(sub) 2530 except (TypeError, ArithmeticError): 2531 raise ArithmeticError, "sub must be a subspace of self" 2532 2533 A, L = self.__quotient_matrices(sub) 2534 quomap = self.hom(A) 2535 quo = quomap.codomain() 2536 liftmap = quo.Hom(self)(L) 2537 2538 return quomap.codomain(), quomap, liftmap 2539 2362 2540 ############################################################################### 2363 2541 # … … 2821 2999 2822 3000 3001 2823 3002 ############################################################################### 2824 3003 # … … 3445 3624 (1, 5, 9) 3446 3625 """ 3447 return self .basis_matrix().linear_combination_of_rows(v)3626 return self(self.basis_matrix().linear_combination_of_rows(v)) 3448 3627 3449 3628 … … 3468 3647 sage: loads(v.dumps()) == v 3469 3648 True 3470 3471 3472 3649 """ 3473 3650 def __init__(self, ambient, gens, check=True, inner_product_matrix=None, -
sage/modules/matrix_morphism.py
r6572 r7474 136 136 if C.is_ambient(): 137 137 return C(v) 138 return C .linear_combination_of_basis(v)138 return C(C.linear_combination_of_basis(v), check=False) 139 139 140 140 def __invert__(self): -
sage/modules/vector_rational_dense.pyx
r6680 r7474 95 95 if isinstance(x, (list, tuple)): 96 96 if len(x) != self._degree: 97 raise ArithmeticError, "entries must be a list of length %s"%self._degree97 raise TypeError, "entries must be a list of length %s"%self._degree 98 98 for i from 0 <= i < self._degree: 99 99 z = Rational(x[i])
Note: See TracChangeset
for help on using the changeset viewer.
