diff --git a/.buildkite/0_webui.yml b/.buildkite/0_webui.yml index d5ba4e0ea7cf9..aed6a5e59d9c3 100644 --- a/.buildkite/0_webui.yml +++ b/.buildkite/0_webui.yml @@ -19,6 +19,6 @@ steps: # Our signed pipelines must have a `signature` or `signature_file` parameter that # verifies the treehash of the pipeline itself and the inputs listed in `inputs` - signed_pipelines: - - pipeline: .buildkite/signed_pipeline_test.yml - signature: "U2FsdGVkX18aZgryp6AJTArgD2uOnVWyFFGVOP5qsY4WbGQ/LVAcYiMEp9cweV+2iht+vmEF949CuuGTeQPA1fKlhPwkG3nZ688752DUB6en9oM2nuL31NoDKWHhpygZ" + #signed_pipelines: + # - pipeline: .buildkite/signed_pipeline_test.yml + # signature: "U2FsdGVkX18aZgryp6AJTArgD2uOnVWyFFGVOP5qsY4WbGQ/LVAcYiMEp9cweV+2iht+vmEF949CuuGTeQPA1fKlhPwkG3nZ688752DUB6en9oM2nuL31NoDKWHhpygZ" diff --git a/.buildkite/embedding.yml b/.buildkite/embedding.yml new file mode 100644 index 0000000000000..faffeb1f7cc87 --- /dev/null +++ b/.buildkite/embedding.yml @@ -0,0 +1,37 @@ +# These steps should only run on `sandbox.jl` machines, not `docker`-isolated ones +# since we need nestable sandboxing. The rootfs images being used here are built from +# the `.buildkite/rootfs_images/llvm-passes.jl` file. +agents: + queue: "julia" + # Only run on `sandbox.jl` machines (not `docker`-isolated ones) since we need nestable sandboxing + sandbox.jl: "true" + os: "linux" + +steps: + - label: "Run embedding tests" + key: embedding + plugins: + - JuliaCI/julia#v1: + version: 1.6 + - staticfloat/sandbox#v1: + rootfs_url: https://github.com/JuliaCI/rootfs-images/releases/download/v1/llvm-passes.tar.gz + rootfs_treehash: "f3ed53f159e8f13edfba8b20ebdb8ece73c1b8a8" + uid: 1000 + gid: 1000 + workspaces: + # Include `/cache/repos` so that our `git` version introspection works. + - "/cache/repos:/cache/repos" + commands: | + prefix="/tmp/prefix" + echo "+++ Build julia, deploy to $${prefix}" + make -j$${JULIA_NUM_CORES} JULIA_PRECOMPILE=0 prefix=$${prefix} install + + embedding_output="/tmp/embedding-test" + echo "+++ Run embedding tests, deploy to $${embedding_output}" + mkdir -p "$${embedding_output}" + make -j$${JULIA_NUM_CORES} -C test/embedding JULIA="$${prefix}/bin/julia" BIN="$${embedding_output}" + + timeout_in_minutes: 60 + notify: + - github_commit_status: + context: "embedding" diff --git a/.buildkite/llvm_passes.yml b/.buildkite/llvm_passes.yml index 862f748c18499..b4311f689d089 100644 --- a/.buildkite/llvm_passes.yml +++ b/.buildkite/llvm_passes.yml @@ -9,21 +9,29 @@ agents: steps: - label: "analyzegc" + key: analyzegc plugins: - JuliaCI/julia#v1: version: 1.6 - staticfloat/sandbox#v1: rootfs_url: https://github.com/JuliaCI/rootfs-images/releases/download/v1/llvm-passes.tar.gz rootfs_treehash: "f3ed53f159e8f13edfba8b20ebdb8ece73c1b8a8" + workspaces: + # Include `/cache/repos` so that our `git` version introspection works. + - "/cache/repos:/cache/repos" commands: | echo "--- Install in-tree LLVM dependencies" - make -j 6 -C deps install-llvm install-clang install-llvm-tools install-libuv install-utf8proc install-unwind + make -j$${JULIA_NUM_CORES} -C deps install-llvm install-clang install-llvm-tools install-libuv install-utf8proc install-unwind echo "+++ run clangsa/analyzegc" - make -j 6 -C test/clangsa - make -j 6 -C src analyzegc + make -j$${JULIA_NUM_CORES} -C test/clangsa + make -j$${JULIA_NUM_CORES} -C src analyzegc timeout_in_minutes: 60 + notify: + - github_commit_status: + context: "analyzegc" - label: "llvmpasses" + key: llvmpasses plugins: - JuliaCI/julia#v1: version: 1.6 @@ -32,9 +40,16 @@ steps: rootfs_treehash: "f3ed53f159e8f13edfba8b20ebdb8ece73c1b8a8" uid: 1000 gid: 1000 + workspaces: + - "/cache/repos:/cache/repos" commands: | - echo "+++ run llvmpasses" - make -j 6 release - make -j 6 -C src install-analysis-deps - make -j 6 -C test/llvmpasses + echo "--- make release" + make -j$${JULIA_NUM_CORES} release JULIA_PRECOMPILE=0 + echo "--- make src/install-analysis-deps" + make -j$${JULIA_NUM_CORES} -C src install-analysis-deps + echo "+++ make test/llvmpasses" + make -j$${JULIA_NUM_CORES} -C test/llvmpasses timeout_in_minutes: 60 + notify: + - github_commit_status: + context: "llvm passes" diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index d76f3fd77bd4f..0dee5f2aaa3f7 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -14,6 +14,8 @@ steps: - label: ":buildkite: Launch unsigned pipelines" commands: | + buildkite-agent pipeline upload .buildkite/whitespace.yml buildkite-agent pipeline upload .buildkite/llvm_passes.yml + buildkite-agent pipeline upload .buildkite/embedding.yml agents: queue: julia diff --git a/.buildkite/whitespace.yml b/.buildkite/whitespace.yml new file mode 100644 index 0000000000000..37fa66f75a3d9 --- /dev/null +++ b/.buildkite/whitespace.yml @@ -0,0 +1,26 @@ +# These steps should only run on `sandbox.jl` machines, not `docker`-isolated ones +# since we need nestable sandboxing. The rootfs images being used here are built from +# the `.buildkite/rootfs_images/llvm-passes.jl` file. +agents: + queue: "julia" + # Only run on `sandbox.jl` machines (not `docker`-isolated ones) since we need nestable sandboxing + sandbox.jl: "true" + os: "linux" + +steps: + - label: "Check whitespace" + key: whitespace + plugins: + - JuliaCI/julia#v1: + version: 1.6 + - staticfloat/sandbox#v1: + rootfs_url: https://github.com/JuliaCI/rootfs-images/releases/download/v1/llvm-passes.tar.gz + rootfs_treehash: "f3ed53f159e8f13edfba8b20ebdb8ece73c1b8a8" + workspaces: + - "/cache/repos:/cache/repos" + commands: | + make -j$${JULIA_NUM_CORES} check-whitespace + timeout_in_minutes: 10 + notify: + - github_commit_status: + context: "whitespace" diff --git a/base/essentials.jl b/base/essentials.jl index 96498a6a30a61..a01598ca4a6ca 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -447,7 +447,9 @@ reinterpret(::Type{T}, x) where {T} = bitcast(T, x) sizeof(obj) Size, in bytes, of the canonical binary representation of the given `DataType` `T`, if any. -Size, in bytes, of object `obj` if it is not `DataType`. +Or the size, in bytes, of object `obj` if it is not a `DataType`. + +See also [`summarysize`](@ref). # Examples ```jldoctest @@ -460,7 +462,7 @@ julia> sizeof(ComplexF64) julia> sizeof(1.0) 8 -julia> sizeof([1.0:10.0;]) +julia> sizeof(collect(1.0:10.0)) 80 ``` diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 9169a1facd8e5..40338fda1564d 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -1103,48 +1103,48 @@ copyto!(::AbstractArray, ::CartesianIndices, ::AbstractArray, ::CartesianIndices # Cartesian to Linear unaliased copy function _unaliased_copyto!(::IndexLinear, dest::AbstractArray, ::IndexCartesian, src::AbstractArray) @_inline_meta - axs = axes(src) - ax, iter = axs[1], CartesianIndices(tail(axs)) - len, j = length(ax), firstindex(dest) + ax = axes1(src) + iter = CartesianIndices(safe_tail(axes(src))) + j = firstindex(dest) - 1 @inbounds for I in iter - n = 0 - while n < len - dest[j + n] = src[first(ax) + n, I.I...] - n += 1 + for i in ax + dest[j += 1] = src[i, I] end - j += len end end # Linear to Cartesian unaliased copy function _unaliased_copyto!(::IndexCartesian, dest::AbstractArray, ::IndexLinear, src::AbstractArray) @_inline_meta - axs = axes(dest) - ax, iter = axs[1], CartesianIndices(tail(axs)) - len, i = length(ax), firstindex(src) - final = lastindex(src) + 1 + ax = axes1(dest) + iter = CartesianIndices(safe_tail(axes(dest))) + len = length(ax) + i, final = firstindex(src) - 1, lastindex(src) @inbounds for I in iter - len′ = min(final - i, len) - n = 0 - while n < len′ - dest[first(ax) + n, I.I...] = src[i + n] - n += 1 + if final - i > len + for j in ax + dest[j, I] = src[i += 1] + end + else + j = first(ax) - 1 + while i < final + dest[j += 1, I] = src[i += 1] + end + break end - (i += len′) == final && break end end -# Cartesian to Cartesian unaliased copy function _unaliased_copyto!(::IndexCartesian, dest::AbstractArray, ::IndexCartesian, src::AbstractArray) @_inline_meta axdest, axsrc = axes(dest), axes(src) - if axdest == axsrc + if axdest == axsrc # shared iterator (manually expended) - ax, iter = axsrc[1], CartesianIndices(tail(axsrc)) + ax = axes1(dest) + iter = CartesianIndices(safe_tail(axdest)) @inbounds for I in iter for i in ax - I′ = CartesianIndex(i, I.I...) - dest[I′] = src[I′] + dest[i, I] = src[i, I] end end else diff --git a/base/summarysize.jl b/base/summarysize.jl index 916214a69f88f..8c0a38d511648 100644 --- a/base/summarysize.jl +++ b/base/summarysize.jl @@ -17,6 +17,20 @@ Compute the amount of memory, in bytes, used by all unique objects reachable fro - `exclude`: specifies the types of objects to exclude from the traversal. - `chargeall`: specifies the types of objects to always charge the size of all of their fields, even if those fields would normally be excluded. + +See also [`sizeof`](@ref). + +# Examples +```jldoctest +julia> Base.summarysize(1.0) +8 + +julia> Base.summarysize(Ref(rand(100))) +848 + +julia> sizeof(Ref(rand(100))) +8 +``` """ function summarysize(obj; exclude = Union{DataType, Core.TypeName, Core.MethodInstance}, diff --git a/contrib/check-whitespace.sh b/contrib/check-whitespace.sh index c380d7bdd2969..ff5bd24ab2cbe 100755 --- a/contrib/check-whitespace.sh +++ b/contrib/check-whitespace.sh @@ -35,3 +35,5 @@ if git --no-pager grep --color -n --full-name -e ' $' -- $file_patterns; then echo "and then a forced push of the correct branch" exit 1 fi + +echo "Whitespace check found no issues" diff --git a/deps/openblas.mk b/deps/openblas.mk index d86663efcbde7..a1ce15100ac4c 100644 --- a/deps/openblas.mk +++ b/deps/openblas.mk @@ -108,12 +108,12 @@ $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-exshift.patch-applied: $(BUILDDIR)/$(OP patch -p1 -f < $(SRCDIR)/patches/openblas-exshift.patch echo 1 > $@ -$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-filter-out-mavx-flag-on-zgemm-kernels.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-openblas-exshift.patch-applied +$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-filter-out-mavx-flag-on-zgemm-kernels.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-exshift.patch-applied cd $(BUILDDIR)/$(OPENBLAS_SRC_DIR) && \ patch -p1 -f < $(SRCDIR)/patches/openblas-filter-out-mavx-flag-on-zgemm-kernels.patch echo 1 > $@ -$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-Only-filter-out-mavx-on-Sandybridge.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-filter-out-mavx-flag-on-zgemm-kernels.patch +$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-Only-filter-out-mavx-on-Sandybridge.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-filter-out-mavx-flag-on-zgemm-kernels.patch-applied cd $(BUILDDIR)/$(OPENBLAS_SRC_DIR) && \ patch -p1 -f < $(SRCDIR)/patches/openblas-Only-filter-out-mavx-on-Sandybridge.patch echo 1 > $@ diff --git a/src/codegen.cpp b/src/codegen.cpp index 3d8ad33516080..d59b312716b2d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1157,7 +1157,7 @@ static void allocate_gc_frame(jl_codectx_t &ctx, BasicBlock *b0); static Value *get_current_task(jl_codectx_t &ctx); static Value *get_current_ptls(jl_codectx_t &ctx); static Value *get_current_signal_page(jl_codectx_t &ctx); -static void CreateTrap(IRBuilder<> &irbuilder); +static void CreateTrap(IRBuilder<> &irbuilder, bool create_new_block = true); static CallInst *emit_jlcall(jl_codectx_t &ctx, Function *theFptr, Value *theF, jl_cgval_t *args, size_t nargs, CallingConv::ID cc); static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction *theFptr, Value *theF, @@ -1456,7 +1456,7 @@ static Constant *undef_value_for_type(Type *T) { return undef; } -static void CreateTrap(IRBuilder<> &irbuilder) +static void CreateTrap(IRBuilder<> &irbuilder, bool create_new_block) { Function *f = irbuilder.GetInsertBlock()->getParent(); Function *trap_func = Intrinsic::getDeclaration( @@ -1464,8 +1464,13 @@ static void CreateTrap(IRBuilder<> &irbuilder) Intrinsic::trap); irbuilder.CreateCall(trap_func); irbuilder.CreateUnreachable(); - BasicBlock *newBB = BasicBlock::Create(irbuilder.getContext(), "after_noret", f); - irbuilder.SetInsertPoint(newBB); + if (create_new_block) { + BasicBlock *newBB = BasicBlock::Create(irbuilder.getContext(), "after_noret", f); + irbuilder.SetInsertPoint(newBB); + } + else { + irbuilder.ClearInsertionPoint(); + } } #if 0 // this code is likely useful, but currently unused @@ -6901,8 +6906,8 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t> if (seq_next >= 0 && (unsigned)seq_next < stmtslen) { workstack.push_back(seq_next); } - else if (!ctx.builder.GetInsertBlock()->getTerminator()) { - ctx.builder.CreateUnreachable(); + else if (ctx.builder.GetInsertBlock() && !ctx.builder.GetInsertBlock()->getTerminator()) { + CreateTrap(ctx.builder, false); } while (!workstack.empty()) { int item = workstack.back(); @@ -6912,7 +6917,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t> cursor = item; return; } - if (seq_next != -1 && !ctx.builder.GetInsertBlock()->getTerminator()) { + if (seq_next != -1 && ctx.builder.GetInsertBlock() && !ctx.builder.GetInsertBlock()->getTerminator()) { come_from_bb[cursor + 1] = ctx.builder.GetInsertBlock(); ctx.builder.CreateBr(nextbb->second); } @@ -7050,7 +7055,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t> if (jl_is_returnnode(stmt)) { jl_value_t *retexpr = jl_returnnode_value(stmt); if (retexpr == NULL) { - ctx.builder.CreateUnreachable(); + CreateTrap(ctx.builder, false); find_next_stmt(-1); continue; } @@ -7059,7 +7064,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t> jl_cgval_t retvalinfo = emit_expr(ctx, retexpr); retvalinfo = convert_julia_type(ctx, retvalinfo, jlrettype); if (retvalinfo.typ == jl_bottom_type) { - ctx.builder.CreateUnreachable(); + CreateTrap(ctx.builder, false); find_next_stmt(-1); continue; } diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 7d0e94fd30783..e37ee264398e9 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -284,7 +284,6 @@ static Value *emit_unboxed_coercion(jl_codectx_t &ctx, Type *to, Value *unboxed) Type *ty = unboxed->getType(); if (ty == to) return unboxed; - assert(to->isIntOrPtrTy() || to->isFloatingPointTy()); bool frompointer = ty->isPointerTy(); bool topointer = to->isPointerTy(); const DataLayout &DL = jl_data_layout; diff --git a/src/jl_exported_data.inc b/src/jl_exported_data.inc index bad61d4ade35a..3cebe459bf643 100644 --- a/src/jl_exported_data.inc +++ b/src/jl_exported_data.inc @@ -5,11 +5,11 @@ XX(jl_abstractstring_type) \ XX(jl_an_empty_string) \ XX(jl_an_empty_vec_any) \ - XX(jl_any_type) \ XX(jl_anytuple_type) \ XX(jl_anytuple_type_type) \ - XX(jl_argument_type) \ + XX(jl_any_type) \ XX(jl_argumenterror_type) \ + XX(jl_argument_type) \ XX(jl_array_any_type) \ XX(jl_array_int32_type) \ XX(jl_array_symbol_type) \ @@ -25,8 +25,8 @@ XX(jl_char_type) \ XX(jl_code_info_type) \ XX(jl_code_instance_type) \ - XX(jl_core_module) \ XX(jl_const_type) \ + XX(jl_core_module) \ XX(jl_datatype_type) \ XX(jl_densearray_type) \ XX(jl_diverror_exception) \ @@ -49,6 +49,7 @@ XX(jl_int32_type) \ XX(jl_int64_type) \ XX(jl_int8_type) \ + XX(jl_interconditional_type) \ XX(jl_interrupt_exception) \ XX(jl_intrinsic_type) \ XX(jl_lineinfonode_type) \ @@ -58,10 +59,10 @@ XX(jl_loaderror_type) \ XX(jl_main_module) \ XX(jl_memory_exception) \ + XX(jl_methoderror_type) \ XX(jl_method_instance_type) \ XX(jl_method_match_type) \ XX(jl_method_type) \ - XX(jl_methoderror_type) \ XX(jl_methtable_type) \ XX(jl_module_type) \ XX(jl_namedtuple_type) \ @@ -71,9 +72,10 @@ XX(jl_nothing) \ XX(jl_nothing_type) \ XX(jl_number_type) \ - XX(jl_partial_struct_type) \ + XX(jl_opaque_closure_type) \ + XX(jl_opaque_closure_typename) \ XX(jl_partial_opaque_type) \ - XX(jl_interconditional_type) \ + XX(jl_partial_struct_type) \ XX(jl_phicnode_type) \ XX(jl_phinode_type) \ XX(jl_pinode_type) \ @@ -95,20 +97,20 @@ XX(jl_true) \ XX(jl_tuple_typename) \ XX(jl_tvar_type) \ - XX(jl_type_type) \ - XX(jl_type_type_mt) \ - XX(jl_type_typename) \ XX(jl_typedslot_type) \ XX(jl_typeerror_type) \ XX(jl_typemap_entry_type) \ XX(jl_typemap_level_type) \ XX(jl_typename_type) \ XX(jl_typeofbottom_type) \ + XX(jl_type_type) \ + XX(jl_type_type_mt) \ + XX(jl_type_typename) \ XX(jl_uint16_type) \ XX(jl_uint32_type) \ XX(jl_uint64_type) \ - XX(jl_uint8_type) \ XX(jl_uint8pointer_type) \ + XX(jl_uint8_type) \ XX(jl_undefref_exception) \ XX(jl_undefvarerror_type) \ XX(jl_unionall_type) \ @@ -116,11 +118,9 @@ XX(jl_upsilonnode_type) \ XX(jl_vararg_type) \ XX(jl_vecelement_typename) \ - XX(jl_void_type) \ XX(jl_voidpointer_type) \ + XX(jl_void_type) \ XX(jl_weakref_type) \ - XX(jl_opaque_closure_type) \ - XX(jl_opaque_closure_typename) // Data symbols that are defined inside the public libjulia #define JL_EXPORTED_DATA_SYMBOLS(XX) \ diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 81e68f3b78ee7..0e82304d82e5c 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -247,6 +247,7 @@ XX(jl_get_nth_field_checked) \ XX(jl_get_nth_field_noalloc) \ XX(jl_getpagesize) \ + XX(jl_get_pgcstack) \ XX(jl_getpid) \ XX(jl_get_ptls_states) \ XX(jl_get_root_symbol) \ @@ -273,10 +274,10 @@ XX(jl_id_start_char) \ XX(jl_idtable_rehash) \ XX(jl_infer_thunk) \ - XX(jl_init_restored_modules) \ XX(jl_init) \ - XX(jl_init_with_image) \ XX(jl_init__threading) \ + XX(jl_init_restored_modules) \ + XX(jl_init_with_image) \ XX(jl_init_with_image__threading) \ XX(jl_install_sigint_handler) \ XX(jl_instantiate_type_in_env) \ @@ -391,6 +392,7 @@ XX(jl_pop_handler) \ XX(jl_preload_sysimg_so) \ XX(jl_prepend_cwd) \ + XX(jl_print_backtrace) \ XX(jl_printf) \ XX(jl_process_events) \ XX(jl_profile_clear_data) \ @@ -541,5 +543,3 @@ XX(jl_vprintf) \ XX(jl_wakeup_thread) \ XX(jl_yield) \ - XX(jl_print_backtrace) \ - XX(jl_get_pgcstack) diff --git a/stdlib/LinearAlgebra/src/cholesky.jl b/stdlib/LinearAlgebra/src/cholesky.jl index 2ad2135da5d9c..bf738d5d203ec 100644 --- a/stdlib/LinearAlgebra/src/cholesky.jl +++ b/stdlib/LinearAlgebra/src/cholesky.jl @@ -110,8 +110,10 @@ positive semi-definite matrix `A`. This is the return type of [`cholesky(_, Val( the corresponding matrix factorization function. The triangular Cholesky factor can be obtained from the factorization `F::CholeskyPivoted` -via `F.L` and `F.U`, and the permutation via `F.p`, where `A[F.p, F.p] ≈ F.U' * F.U ≈ F.L * F.L'`, -or alternatively `A ≈ F.U[:, F.p]' * F.U[:, F.p] ≈ F.L[F.p, :] * F.L[F.p, :]'`. +via `F.L` and `F.U`, and the permutation via `F.p`, where `A[F.p, F.p] ≈ Ur' * Ur ≈ Lr * Lr'` +with `Ur = F.U[1:F.rank, :]` and `Lr = F.L[:, 1:F.rank]`, or alternatively +`A ≈ Up' * Up ≈ Lp * Lp'` with `Up = F.U[1:F.rank, invperm(F.p)]` and +`Lp = F.L[invperm(F.p), 1:F.rank]`. The following functions are available for `CholeskyPivoted` objects: [`size`](@ref), [`\\`](@ref), [`inv`](@ref), [`det`](@ref), and [`rank`](@ref). @@ -120,25 +122,28 @@ Iterating the decomposition produces the components `L` and `U`. # Examples ```jldoctest -julia> A = [4. 12. -16.; 12. 37. -43.; -16. -43. 98.] -3×3 Matrix{Float64}: - 4.0 12.0 -16.0 - 12.0 37.0 -43.0 - -16.0 -43.0 98.0 +julia> X = [1.0, 2.0, 3.0, 4.0]; -julia> C = cholesky(A, Val(true)) +julia> A = X * X'; + +julia> C = cholesky(A, Val(true), check = false) CholeskyPivoted{Float64, Matrix{Float64}} -U factor with rank 3: -3×3 UpperTriangular{Float64, Matrix{Float64}}: - 9.89949 -4.34366 -1.61624 - ⋅ 4.25825 1.1694 - ⋅ ⋅ 0.142334 +U factor with rank 1: +4×4 UpperTriangular{Float64, Matrix{Float64}}: + 4.0 2.0 3.0 1.0 + ⋅ 0.0 6.0 2.0 + ⋅ ⋅ 9.0 3.0 + ⋅ ⋅ ⋅ 1.0 permutation: -3-element Vector{Int64}: - 3 +4-element Vector{Int64}: + 4 2 + 3 1 +julia> C.U[1:C.rank, :]' * C.U[1:C.rank, :] ≈ A[C.p, C.p] +true + julia> l, u = C; # destructuring via iteration julia> l == C.L && u == C.U @@ -403,8 +408,9 @@ and return a [`CholeskyPivoted`](@ref) factorization. The matrix `A` can either or [`Hermitian`](@ref) [`StridedMatrix`](@ref) or a *perfectly* symmetric or Hermitian `StridedMatrix`. The triangular Cholesky factor can be obtained from the factorization `F` via `F.L` and `F.U`, -and the permutation via `F.p`, where `A[F.p, F.p] ≈ F.U' * F.U ≈ F.L * F.L'`, or alternatively -`A ≈ F.U[:, F.p]' * F.U[:, F.p] ≈ F.L[F.p, :] * F.L[F.p, :]'`. +and the permutation via `F.p`, where `A[F.p, F.p] ≈ Ur' * Ur ≈ Lr * Lr'` with `Ur = F.U[1:F.rank, :]` +and `Lr = F.L[:, 1:F.rank]`, or alternatively `A ≈ Up' * Up ≈ Lp * Lp'` with +`Up = F.U[1:F.rank, invperm(F.p)]` and `Lp = F.L[invperm(F.p), 1:F.rank]`. The following functions are available for `CholeskyPivoted` objects: [`size`](@ref), [`\\`](@ref), [`inv`](@ref), [`det`](@ref), and [`rank`](@ref). @@ -421,26 +427,26 @@ validity (via [`issuccess`](@ref)) lies with the user. # Examples ```jldoctest -julia> A = [4. 12. -16.; 12. 37. -43.; -16. -43. 98.] -3×3 Matrix{Float64}: - 4.0 12.0 -16.0 - 12.0 37.0 -43.0 - -16.0 -43.0 98.0 +julia> X = [1.0, 2.0, 3.0, 4.0]; + +julia> A = X * X'; -julia> C = cholesky(A, Val(true)) +julia> C = cholesky(A, Val(true), check = false) CholeskyPivoted{Float64, Matrix{Float64}} -U factor with rank 3: -3×3 UpperTriangular{Float64, Matrix{Float64}}: - 9.89949 -4.34366 -1.61624 - ⋅ 4.25825 1.1694 - ⋅ ⋅ 0.142334 +U factor with rank 1: +4×4 UpperTriangular{Float64, Matrix{Float64}}: + 4.0 2.0 3.0 1.0 + ⋅ 0.0 6.0 2.0 + ⋅ ⋅ 9.0 3.0 + ⋅ ⋅ ⋅ 1.0 permutation: -3-element Vector{Int64}: - 3 +4-element Vector{Int64}: + 4 2 + 3 1 -julia> C.U[:, C.p]' * C.U[:, C.p] ≈ A +julia> C.U[1:C.rank, :]' * C.U[1:C.rank, :] ≈ A[C.p, C.p] true julia> l, u = C; # destructuring via iteration diff --git a/stdlib/SparseArrays/src/sparsematrix.jl b/stdlib/SparseArrays/src/sparsematrix.jl index bcc518f527f63..af5eb4e4ab726 100644 --- a/stdlib/SparseArrays/src/sparsematrix.jl +++ b/stdlib/SparseArrays/src/sparsematrix.jl @@ -81,6 +81,7 @@ size(S::SparseMatrixCSC) = (getfield(S, :m), getfield(S, :n)) _goodbuffers(S::SparseMatrixCSC) = _goodbuffers(size(S)..., getcolptr(S), getrowval(S), nonzeros(S)) _checkbuffers(S::SparseMatrixCSC) = (@assert _goodbuffers(S); S) +_checkbuffers(S::Union{Adjoint, Transpose}) = (_checkbuffers(parent(S)); S) function _goodbuffers(m, n, colptr, rowval, nzval) (length(colptr) == n + 1 && colptr[end] - 1 == length(rowval) == length(nzval)) @@ -125,6 +126,8 @@ julia> nnz(A) """ nnz(S::AbstractSparseMatrixCSC) = Int(getcolptr(S)[size(S, 2) + 1]) - 1 nnz(S::ReshapedArray{<:Any,1,<:AbstractSparseMatrixCSC}) = nnz(parent(S)) +nnz(S::Adjoint{<:Any,<:AbstractSparseMatrixCSC}) = nnz(parent(S)) +nnz(S::Transpose{<:Any,<:AbstractSparseMatrixCSC}) = nnz(parent(S)) nnz(S::UpperTriangular{<:Any,<:AbstractSparseMatrixCSC}) = nnz1(S) nnz(S::LowerTriangular{<:Any,<:AbstractSparseMatrixCSC}) = nnz1(S) nnz(S::SparseMatrixCSCView) = nnz1(S) @@ -215,6 +218,7 @@ nzrange(S::SparseMatrixCSCView, col::Integer) = nzrange(S.parent, S.indices[2][c nzrange(S::UpperTriangular{<:Any,<:SparseMatrixCSCUnion}, i::Integer) = nzrangeup(S.data, i) nzrange(S::LowerTriangular{<:Any,<:SparseMatrixCSCUnion}, i::Integer) = nzrangelo(S.data, i) +const AbstractSparseMatrixCSCInclAdjointAndTranspose = Union{AbstractSparseMatrixCSC,Adjoint{<:Any,<:AbstractSparseMatrixCSC},Transpose{<:Any,<:AbstractSparseMatrixCSC}} function Base.isstored(A::AbstractSparseMatrixCSC, i::Integer, j::Integer) @boundscheck checkbounds(A, i, j) rows = rowvals(A) @@ -224,11 +228,21 @@ function Base.isstored(A::AbstractSparseMatrixCSC, i::Integer, j::Integer) return false end -Base.replace_in_print_matrix(A::AbstractSparseMatrix, i::Integer, j::Integer, s::AbstractString) = +function Base.isstored(A::Union{Adjoint{<:Any,<:AbstractSparseMatrixCSC},Transpose{<:Any,<:AbstractSparseMatrixCSC}}, i::Integer, j::Integer) + @boundscheck checkbounds(A, i, j) + cols = rowvals(parent(A)) + for istored in nzrange(parent(A), i) + j == cols[istored] && return true + end + return false +end + +Base.replace_in_print_matrix(A::AbstractSparseMatrixCSCInclAdjointAndTranspose, i::Integer, j::Integer, s::AbstractString) = Base.isstored(A, i, j) ? s : Base.replace_with_centered_mark(s) -function Base.array_summary(io::IO, S::AbstractSparseMatrixCSC, dims::Tuple{Vararg{Base.OneTo}}) +function Base.array_summary(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose, dims::Tuple{Vararg{Base.OneTo}}) _checkbuffers(S) + xnnz = nnz(S) m, n = size(S) print(io, m, "×", n, " ", typeof(S), " with ", xnnz, " stored ", @@ -236,8 +250,8 @@ function Base.array_summary(io::IO, S::AbstractSparseMatrixCSC, dims::Tuple{Vara nothing end -# called by `show(io, MIME("text/plain"), ::AbstractSparseMatrixCSC)` -function Base.print_array(io::IO, S::AbstractSparseMatrixCSC) +# called by `show(io, MIME("text/plain"), ::AbstractSparseMatrixCSCInclAdjointAndTranspose)` +function Base.print_array(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose) if max(size(S)...) < 16 Base.print_matrix(io, S) else @@ -246,7 +260,7 @@ function Base.print_array(io::IO, S::AbstractSparseMatrixCSC) end # always show matrices as `sparse(I, J, K)` -function Base.show(io::IO, S::AbstractSparseMatrixCSC) +function Base.show(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose) _checkbuffers(S) # can't use `findnz`, because that expects all values not to be #undef I = rowvals(S) @@ -257,7 +271,7 @@ function Base.show(io::IO, S::AbstractSparseMatrixCSC) end const brailleBlocks = UInt16['⠁', '⠂', '⠄', '⡀', '⠈', '⠐', '⠠', '⢀'] -function _show_with_braille_patterns(io::IO, S::AbstractSparseMatrixCSC) +function _show_with_braille_patterns(io::IO, S::AbstractSparseMatrixCSCInclAdjointAndTranspose) m, n = size(S) (m == 0 || n == 0) && return show(io, MIME("text/plain"), S) @@ -291,28 +305,43 @@ function _show_with_braille_patterns(io::IO, S::AbstractSparseMatrixCSC) brailleGrid = fill(UInt16(10240), (scaleWidth - 1) ÷ 2 + 2, (scaleHeight - 1) ÷ 4 + 1) brailleGrid[end, :] .= '\n' - rvals = rowvals(S) + rvals = rowvals(parent(S)) rowscale = max(1, scaleHeight - 1) / max(1, m - 1) colscale = max(1, scaleWidth - 1) / max(1, n - 1) - @inbounds for j = 1:n - # Scale the column index `j` to the best matching column index - # of a matrix of size `scaleHeight × scaleWidth` - sj = round(Int, (j - 1) * colscale + 1) - for x in nzrange(S, j) - # Scale the row index `i` to the best matching row index + if isa(S, AbstractSparseMatrixCSC) + @inbounds for j = 1:n + # Scale the column index `j` to the best matching column index # of a matrix of size `scaleHeight × scaleWidth` - si = round(Int, (rvals[x] - 1) * rowscale + 1) - - # Given the index pair `(si, sj)` of the scaled matrix, - # calculate the corresponding triple `(k, l, p)` such that the - # element at `(si, sj)` can be found at position `(k, l)` in the - # braille grid `brailleGrid` and corresponds to the 1-dot braille - # character `brailleBlocks[p]` - k = (sj - 1) ÷ 2 + 1 - l = (si - 1) ÷ 4 + 1 - p = ((sj - 1) % 2) * 4 + ((si - 1) % 4 + 1) - - brailleGrid[k, l] |= brailleBlocks[p] + sj = round(Int, (j - 1) * colscale + 1) + for x in nzrange(S, j) + # Scale the row index `i` to the best matching row index + # of a matrix of size `scaleHeight × scaleWidth` + si = round(Int, (rvals[x] - 1) * rowscale + 1) + + # Given the index pair `(si, sj)` of the scaled matrix, + # calculate the corresponding triple `(k, l, p)` such that the + # element at `(si, sj)` can be found at position `(k, l)` in the + # braille grid `brailleGrid` and corresponds to the 1-dot braille + # character `brailleBlocks[p]` + k = (sj - 1) ÷ 2 + 1 + l = (si - 1) ÷ 4 + 1 + p = ((sj - 1) % 2) * 4 + ((si - 1) % 4 + 1) + + brailleGrid[k, l] |= brailleBlocks[p] + end + end + else + # If `S` is a adjoint or transpose of a sparse matrix we invert the + # roles of the indices `i` and `j` + @inbounds for i = 1:m + si = round(Int, (i - 1) * rowscale + 1) + for x in nzrange(parent(S), i) + sj = round(Int, (rvals[x] - 1) * colscale + 1) + k = (sj - 1) ÷ 2 + 1 + l = (si - 1) ÷ 4 + 1 + p = ((sj - 1) % 2) * 4 + ((si - 1) % 4 + 1) + brailleGrid[k, l] |= brailleBlocks[p] + end end end foreach(c -> print(io, Char(c)), @view brailleGrid[1:end-1]) diff --git a/stdlib/SparseArrays/test/sparse.jl b/stdlib/SparseArrays/test/sparse.jl index 2e07f42182a5e..221997a8f3384 100644 --- a/stdlib/SparseArrays/test/sparse.jl +++ b/stdlib/SparseArrays/test/sparse.jl @@ -2365,22 +2365,70 @@ end for c in unstored_indices @test Base.isstored(A, c[1], c[2]) == false end + + # `isstored` for adjoint and tranposed matrices: + for trans in (adjoint, transpose) + B = trans(A) + stored_indices = [CartesianIndex(j, i) for (j, i) in zip(J, I)] + unstored_indices = [c for c in CartesianIndices((n, m)) if !(c in stored_indices)] + for c in stored_indices + @test Base.isstored(B, c[1], c[2]) == true + end + for c in unstored_indices + @test Base.isstored(B, c[1], c[2]) == false + end + end end @testset "show" begin io = IOBuffer() - show(io, MIME"text/plain"(), spzeros(Float64, Int64, 0, 0)) - @test String(take!(io)) == "0×0 SparseArrays.SparseMatrixCSC{Float64, Int64} with 0 stored entries" - show(io, MIME"text/plain"(), sparse(Int64[1], Int64[1], [1.0])) - @test String(take!(io)) == "1×1 SparseArrays.SparseMatrixCSC{Float64, Int64} with 1 stored entry:\n 1.0" - show(io, MIME"text/plain"(), spzeros(Float32, Int64, 2, 2)) - @test String(take!(io)) == "2×2 SparseArrays.SparseMatrixCSC{Float32, Int64} with 0 stored entries:\n ⋅ ⋅ \n ⋅ ⋅ " + + A = spzeros(Float64, Int64, 0, 0) + for (transform, showstring) in zip( + (identity, adjoint, transpose), ( + "0×0 $SparseMatrixCSC{Float64, Int64} with 0 stored entries", + "0×0 $Adjoint{Float64, $SparseMatrixCSC{Float64, Int64}} with 0 stored entries", + "0×0 $Transpose{Float64, $SparseMatrixCSC{Float64, Int64}} with 0 stored entries" + )) + show(io, MIME"text/plain"(), transform(A)) + @test String(take!(io)) == showstring + end + + A = sparse(Int64[1], Int64[1], [1.0]) + for (transform, showstring) in zip( + (identity, adjoint, transpose), ( + "1×1 $SparseMatrixCSC{Float64, Int64} with 1 stored entry:\n 1.0", + "1×1 $Adjoint{Float64, $SparseMatrixCSC{Float64, Int64}} with 1 stored entry:\n 1.0", + "1×1 $Transpose{Float64, $SparseMatrixCSC{Float64, Int64}} with 1 stored entry:\n 1.0", + )) + show(io, MIME"text/plain"(), transform(A)) + @test String(take!(io)) == showstring + end + + A = spzeros(Float32, Int64, 2, 2) + for (transform, showstring) in zip( + (identity, adjoint, transpose), ( + "2×2 $SparseMatrixCSC{Float32, Int64} with 0 stored entries:\n ⋅ ⋅ \n ⋅ ⋅ ", + "2×2 $Adjoint{Float32, $SparseMatrixCSC{Float32, Int64}} with 0 stored entries:\n ⋅ ⋅ \n ⋅ ⋅ ", + "2×2 $Transpose{Float32, $SparseMatrixCSC{Float32, Int64}} with 0 stored entries:\n ⋅ ⋅ \n ⋅ ⋅ ", + )) + show(io, MIME"text/plain"(), transform(A)) + @test String(take!(io)) == showstring + end A = sparse(Int64[1, 1], Int64[1, 2], [1.0, 2.0]) - show(io, MIME"text/plain"(), A) - @test String(take!(io)) == "1×2 SparseArrays.SparseMatrixCSC{Float64, Int64} with 2 stored entries:\n 1.0 2.0" - _show_with_braille_patterns(convert(IOContext, io), A) - @test String(take!(io)) == "⠉" + for (transform, showstring, braille) in zip( + (identity, adjoint, transpose), ( + "1×2 $SparseMatrixCSC{Float64, Int64} with 2 stored entries:\n 1.0 2.0", + "2×1 $Adjoint{Float64, $SparseMatrixCSC{Float64, Int64}} with 2 stored entries:\n 1.0\n 2.0", + "2×1 $Transpose{Float64, $SparseMatrixCSC{Float64, Int64}} with 2 stored entries:\n 1.0\n 2.0", + ), + ("⠉", "⠃", "⠃")) + show(io, MIME"text/plain"(), transform(A)) + @test String(take!(io)) == showstring + _show_with_braille_patterns(convert(IOContext, io), transform(A)) + @test String(take!(io)) == braille + end # every 1-dot braille pattern for (i, b) in enumerate(split("⠁⠂⠄⡀⠈⠐⠠⢀", "")) @@ -2392,28 +2440,50 @@ end # empty braille pattern Char(10240) A = spzeros(Int64, Int64, 4, 2) - _show_with_braille_patterns(convert(IOContext, io), A) - @test String(take!(io)) == "" * Char(10240) + for (transform, braille) in zip( + (identity, adjoint, transpose), + ("" * Char(10240), "" * Char(10240)^2, "" * Char(10240)^2)) + _show_with_braille_patterns(convert(IOContext, io), transform(A)) + @test String(take!(io)) == braille + end A = sparse(Int64[1, 2, 4, 2, 3], Int64[1, 1, 1, 2, 2], Int64[1, 1, 1, 1, 1], 4, 2) - show(io, MIME"text/plain"(), A) - @test String(take!(io)) == "4×2 SparseArrays.SparseMatrixCSC{Int64, Int64} with 5 stored entries:\n 1 ⋅\n 1 1\n ⋅ 1\n 1 ⋅" - _show_with_braille_patterns(convert(IOContext, io), A) - @test String(take!(io)) == "⡳" + for (transform, showstring, braille) in zip( + (identity, adjoint, transpose), ( + "4×2 $SparseMatrixCSC{Int64, Int64} with 5 stored entries:\n 1 ⋅\n 1 1\n ⋅ 1\n 1 ⋅", + "2×4 $Adjoint{Int64, $SparseMatrixCSC{Int64, Int64}} with 5 stored entries:\n 1 1 ⋅ 1\n ⋅ 1 1 ⋅", + "2×4 $Transpose{Int64, $SparseMatrixCSC{Int64, Int64}} with 5 stored entries:\n 1 1 ⋅ 1\n ⋅ 1 1 ⋅", + ), + ("⡳", "⠙⠊", "⠙⠊")) + show(io, MIME"text/plain"(), transform(A)) + @test String(take!(io)) == showstring + _show_with_braille_patterns(convert(IOContext, io), transform(A)) + @test String(take!(io)) == braille + end A = sparse(Int64[1, 3, 2, 4], Int64[1, 1, 2, 2], Int64[1, 1, 1, 1], 7, 3) - show(io, MIME"text/plain"(), A) - @test String(take!(io)) == "7×3 SparseArrays.SparseMatrixCSC{Int64, Int64} with 4 stored entries:\n 1 ⋅ ⋅\n ⋅ 1 ⋅\n 1 ⋅ ⋅\n ⋅ 1 ⋅\n ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅" - _show_with_braille_patterns(convert(IOContext, io), A) - @test String(take!(io)) == "⢕" * Char(10240) * "\n" * Char(10240)^2 + for (transform, showstring, braille) in zip( + (identity, adjoint, transpose), ( + "7×3 $SparseMatrixCSC{Int64, Int64} with 4 stored entries:\n 1 ⋅ ⋅\n ⋅ 1 ⋅\n 1 ⋅ ⋅\n ⋅ 1 ⋅\n ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅", + "3×7 $Adjoint{Int64, $SparseMatrixCSC{Int64, Int64}} with 4 stored entries:\n 1 ⋅ 1 ⋅ ⋅ ⋅ ⋅\n ⋅ 1 ⋅ 1 ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅", + "3×7 $Transpose{Int64, $SparseMatrixCSC{Int64, Int64}} with 4 stored entries:\n 1 ⋅ 1 ⋅ ⋅ ⋅ ⋅\n ⋅ 1 ⋅ 1 ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅", + ), + ("⢕" * Char(10240) * "\n" * Char(10240)^2, "⠑⠑" * Char(10240)^2, "⠑⠑" * Char(10240)^2)) + show(io, MIME"text/plain"(), transform(A)) + @test String(take!(io)) == showstring + _show_with_braille_patterns(convert(IOContext, io), transform(A)) + @test String(take!(io)) == braille + end A = sparse(Int64[1:10;], Int64[1:10;], fill(Float64(1), 10)) - _show_with_braille_patterns(convert(IOContext, io), A) brailleString = "⠑⢄" * Char(10240)^3 * "\n" * Char(10240)^2 * "⠑⢄" * Char(10240) * "\n" * Char(10240)^4 * "⠑" - @test String(take!(io)) == brailleString + for transform in (identity, adjoint, transpose) + _show_with_braille_patterns(convert(IOContext, io), transform(A)) + @test String(take!(io)) == brailleString + end # Issue #30589 - @test repr("text/plain", sparse([true true])) == "1×2 SparseArrays.SparseMatrixCSC{Bool, $Int} with 2 stored entries:\n 1 1" + @test repr("text/plain", sparse([true true])) == "1×2 $SparseMatrixCSC{Bool, $Int} with 2 stored entries:\n 1 1" function _filled_sparse(m::Integer, n::Integer) C = CartesianIndices((m, n))[:] diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index df29a339d5a85..f232b246a9fc9 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -593,3 +593,7 @@ f41438(y) = y[].x @test B41438.body.layout === C_NULL @test f41438(Ref{A41438}(A41438(C_NULL))) === C_NULL @test f41438(Ref{B41438}(B41438(C_NULL))) === C_NULL + +# issue #41157 +f41157(a, b) = a[1] = b[1] +@test_throws BoundsError f41157(Tuple{Int}[], Tuple{Union{}}[])