Changelog
All notable changes to openpls-engine. The format follows Keep a Changelog and the project adheres to Semantic Versioning.
The public API is stable as of 1.0.0. Tagged releases trigger a GitHub Actions workflow that builds the package and publishes it to PyPI via OIDC trusted publishing.
1.10.0
Released 2026-07-06.
Three additive research-methodology diagnostics: directional hypothesis testing on LV correlations (nomological validity), the Lindell-Whitney marker-variable common-method-bias check, and the paired Cross-Validated Predictive Ability Test (CVPAT) that reviewers increasingly expect alongside PLSpredict. All APIs are additive.
Added
Plspm.nomological_validity(hypotheses, alpha=0.05)- directional hypothesis testing on latent-variable correlations. Each hypothesis is a triple(source, target, expected_sign)withexpected_signin{"+", "-"}; the method evaluates whether the Pearson correlation between the two LV score columns matches the hypothesised direction via a one-sided t-test withn − 2degrees of freedom. Verdict is"supported"when the sign matches AND the one-sided p-value is belowalpha(Cronbach & Meehl 1955; Hair, Hult, Ringle & Sarstedt 2022). Returns aNomologicalValidityobject withtable()(per-hypothesis verdict) andcorrelations()(full LV correlation matrix).- Common Method Bias diagnostic (Lindell & Whitney 2001 marker-variable procedure) via
Plspm.cmb_lindell_whitney(marker, alpha=0.05). Takes a marker variable theoretically unrelated to any substantive construct, estimates the common method variance proxyr_Mas the signed smallest-absolute marker-construct correlation, and partial-correlates every substantive LV pair byr_Mviar_A = (r_U − r_M) / (1 − r_M). Two-sided p-values are reported for both the unadjusted (n − 2df) and adjusted (n − 3df) correlations; the per-pair verdict is"lost_significance"/"gained_significance"/"unchanged". Marker rows with missing values use pairwise deletion. See Lindell & Whitney (2001) and Malhotra, Kim & Patil (2006). - Cross-Validated Predictive Ability Test (CVPAT, Liengaard et al. 2021) via
Plspm.cvpat(benchmark="IA", k=10, repeats=1, seed=42, alpha=0.05). Runsk-fold cross-validation, accumulates per-observation squared prediction errors across endogenous indicators under (a) PLS-SEM and (b) a benchmark, then runs a one-sided paired t-test on the loss differencesd_i = loss_i^PLS − loss_i^benchmarkunderH_0: E[d] ≥ 0. Two benchmarks are supported:"IA"(indicator average, the naive Q²_predict baseline) and"LM"(direct-antecedents linear regression on the target indicator).overall()returns the model-level test,per_construct()returns one test per endogenous LV, andlosses()exposes the per-observation loss table. Complements PLSpredict (Shmueli et al. 2019), which compares PLS to LM one indicator at a time without a significance test on the difference. See Liengaard et al. (2021) in Decision Sciences 52(2).
1.9.0
Released 2026-06-19.
Addresses two engine-side items from Florian Schuberth’s technical review of OpenPLS: HTMT/HTMT2 are now correctly gated to reflective constructs, and the Unidimensionality class has been renamed to Reliability to match what it actually measures.
Changed
- HTMT and HTMT2 now return
NaNfor any latent-variable pair that involves a formative (Mode B) construct. Both metrics estimate the correlation between reflectively measured latent variables; applying them to formative blocks produced misleading discriminant-validity numbers. The reflective-only restriction is now enforced insideopenpls.htmt.HTMTandopenpls.htmt2.HTMT2. Mode A pairs are unaffected. Unidimensionality→Reliability. The class that computes Cronbach’s α and Dillon-Goldstein ρ_c has been renamed toopenpls.reliability.Reliability; those metrics measure reliability, not unidimensionality (a stricter psychometric concept).Plspm.reliability()is the new accessor.
Deprecated
openpls.unidimensionality.UnidimensionalityandPlspm.unidimensionality()now emitDeprecationWarningand forward to the new names. Behaviour is identical; the old names will be removed in a future major release.
1.8.0
Released 2026-06-13.
Maintenance release. No engine API changes, no behavioral changes. Fixes the PyPI project page (its Markdown renderer cannot resolve repo-relative links) and locks the developer / CI / Read-the-Docs environment to a known-good set of dependency versions verified to install across Python 3.10–3.13.
Changed
- PyPI project page now links the Changelog to
https://openpls.app/engine/changelog/. PyPI strips repo-relativeCHANGELOG.mdlinks from rendered READMEs, so the previous link silently vanished on the project page. The[project.urls]table inpyproject.tomlalso gains an explicitChangelogentry which surfaces in the PyPI sidebar. requirements.txtnow pins exact versions for the developer toolchain (pandas, numpy, scipy, statsmodels, scikit-learn, pytest, setuptools, wheel, twine, sphinx, m2r) instead of unpinned floats. The install metadata inpyproject.tomlkeeps the loose floor ranges so consumers are not over-constrained. The pinned set is the matrix the CI job and the Read-the-Docs build run against on every push.
1.7.0
Released 2026-06-12.
Extends the PLSc consistent-PLS layer with first-class direct / indirect / total effects and specific indirect effects, so mediation analysis on a common-factor model no longer carries the composite-model attenuation forward into the chain product.
Added
PLSc.effects()- direct / indirect / total effects walked over the dis-attenuated structural DAG. Drop-in replacement forPlspm.effects()with the same column layout (from,to,direct,indirect,total) and"A -> B"index labels. Required when interpreting the model as a common-factor (covariance-based) one, since the composite-basedPlspm.effects()would otherwise carry the PLS-SEM measurement-error attenuation forward into the indirect / total cells.PLSc.specific_indirect_effects(source, target, through=None)- point estimates of mediation chains on the corrected paths. Either enumerates everysource -> ... -> targetchain in the structural DAG (default) or evaluates an explicitthrough=[...]mediator chain (Zhao/Lynch/Chen 2010; Nitzl, Roldán and Cepeda 2016). Multiplies the dis-attenuated PLSc β along the chain, identical interface and chain-label convention asPlspm.specific_indirect_effects/Bootstrap.specific_indirect_effects.
1.6.0
Released 2026-06-12.
Adds bootstrap-based multi-group analysis for the two-group case, the canonical disattenuated PLSc quality panel (AVE / ρ_c / SRMR / BIC / HTMT / VIF on the corrected metric), Henseler-convention IPMA indicator importance, MICOM’s raw variance-difference statistic, PLSpredict’s earliest-antecedents LM benchmark, and unified bootstrap inference tables on LongBootstrap. All APIs are additive - no existing behaviour changes.
Added
-
Bootstrap-based Multi-Group Analysis via
openpls.bootstrap_mga.BootstrapMGA. Complements the permutation-basedopenpls.mga.MGAwith bootstrap inference on the difference between exactly two groups. For every path coefficient, outer loading, outer weight, total effect, and specific / total indirect effect, three pairwise difference tests are reported side by side:- Henseler (2007) distribution-based one- / two-tailed p-values from pairwise comparison of the two per-group bootstrap resampling distributions (Sarstedt, Henseler and Ringle 2011).
- Chin (2000) parametric pooled-variance t-test on bootstrap standard errors (Hair, Hult, Ringle and Sarstedt 2022, A Primer on PLS-SEM, 3rd ed., Eq. 4.7).
- Welch-Satterthwaite unequal-variance variant (Eq. 4.8).
Per-group raw bootstrap summaries (
original,mean,std_error,t_value,p_value) and bias-corrected percentile confidence intervals are emitted alongside each contrast, matching the layout of the SmartPLS Bootstrap MGA output table. Raw (unflipped) resamples are used throughout to match the SmartPLS “no sign changes” option; sign-flipping per group would invalidate cross-group Henseler comparisons. Specific / total indirect effects are computed inline from per-grouppathCoefficientsresamples viaenumerate_chains. UseBootstrapMGAfor parametric / Welch parity and SmartPLS-style two-group reporting; useMGAfor permutation-based testing across more than two groups. -
Unified bootstrap inference tables on
LongBootstrapvia the newinferenceproperty. Returns a dict keyed bypathCoefficients,outerLoadings,outerWeights,specificIndirectEffects,totalIndirectEffects, andtotalEffects. Each DataFrame carries the canonical inference columnsoriginal,mean,std_error,t_value,p_value,ci_percentile_2_5,ci_percentile_97_5,ci_bc_2_5,ci_bc_97_5. The bias-corrected CI uses the Efron (1987) z₀ formula and the p-value is computed from the two-sided recentred bootstrap distribution (Davison and Hinkley 1997 §4.4). Resamples remain accessible via the newresamples,path_keys,outer_keys, andlv_namesproperties for downstream analyses (MGA, custom tests).
Changed
-
LongBootstrap.paths()/loadings()/weights()/total_effects()now expose both percentile and bias-corrected CI columns alongside the existingci_lower/ci_upper(which continue to hold the BC bounds for backwards compatibility). -
PLSc disattenuated reflective-LV quality panel - closes the gap that previously mixed PLSc paths / loadings with PLS-SEM AVE / ρ_c / SRMR / BIC / HTMT / VIF (Dijkstra and Henseler 2015):
PLSc.ave()- Average Variance Extracted on the PLSc loadings,λ_c = w · sqrt(rho_A) / (w'w).PLSc.rho_c()- Jöreskog’s composite reliability evaluated on the PLSc loadings.PLSc.htmt()- disattenuated construct-correlation magnitude (consistent estimator of the latent correlation under congeneric reflective measurement; same 0.85 / 0.90 thresholds as HTMT).PLSc.srmr()/PLSc.d_uls()- saturated-model fit on the PLSc implied indicator correlation matrixΣ̂_c = Λ_c Φ_c Λ_cᵀ, whereΦ_cis the dis-attenuated LV correlation matrix.PLSc.bic()- Bayesian Information Criterion per endogenous LV using the corrected R².PLSc.vif_inner()- inner VIF per endogenous LV computed on the dis-attenuated correlation metric.PLSc.summary()additionally returnsave,rho_c, andbiccolumns (existingrho_a,r_squared,r_squared_adjunchanged). ThePlspmaccessors (inner_summary,model_fit,vif,htmt, …) still return the uncorrected composite-model values so both interpretations remain available side by side.
-
IPMA.indicators()now emits two additional columns matching the Henseler IPMA convention (Ringle and Sarstedt 2016):indicator_importance(=outer_weight × lv_importance, the indicator’s total effect on the IPMA target) andhenseler_normalized_weight(=indicator_importance / lv_importance, the value SmartPLS-style IPMA tables report under “Normalized Weight”). The legacynormalized_weight(weight ÷ Σ weight per LV) remains for backwards compatibility. -
MICOM.step3()now emits an additionalvar_diffcolumn (=var_a − var_b) alongside the existinglog_var_ratio(=log(var_a / var_b), Henseler / Ringle / Sarstedt 2016 §3.4). Both quantities are zero under H₀ and share the same sign; the raw difference matches the convention used by SmartPLS-style validation tables, while the log-ratio remains the canonical Henseler test statistic. -
Plspm.predict()/PLSPredictaccepts a newlm_predictor_setparameter selecting the LM benchmark’s regressor block:"direct"(default, backwards-compatible) - the LV’s direct path predecessors."earliest_antecedents"- walks upstream through every mediator and uses only the exogenous LVs at the top of the structural DAG, per the Shmueli / Hair / Ringle 2019 PLSpredict convention.
The PLS-side predictions are unaffected; only the LM benchmark moves.
1.5.0
Released 2026-06-10.
Adds the canonical pre-MGA measurement-invariance check so engine users can verify that composite constructs are comparable across two groups before interpreting group differences. Single additive feature, no existing behaviour changes.
Added
-
MICOM - Measurement Invariance of Composite Models (Henseler, Ringle and Sarstedt 2016) via
Plspm.micom(data, grouping_column, group_a, group_b, iterations=1000, seed=42). Three-step procedure:- Step 1 - Configural invariance is guaranteed by construction: the same
Configis reused for both groups (audit trail viaMICOM.group_sizes()). - Step 2 - Compositional invariance. Per construct, computes
c = w_A' Σ w_B / sqrt((w_A' Σ w_A)(w_B' Σ w_B))between the group-A and group-B weight vectors evaluated on the pooled indicator covariance, then testsH_0: c = 1with a one-sided lower-tail permutation test (the permutation distribution clusters near1under the null; an observedcdeep in the lower tail rejects invariance). Sign indeterminacy is handled by aligning each permutation’s weight direction before computingc. - Step 3 - Equality of composite means and variances. Applies pooled-fit weights to standardized indicators to produce common-scale composite scores; mean differences and
log(var_A / var_B)are then tested with two-sided label-shuffling permutations. Step 3 reuses the pooled weights inside each iteration instead of refitting PLS, so it is far cheaper than Step 2. MICOM.summary()collapses the three steps into a per-construct verdict -"full"(Step 2 + Step 3 pass),"partial"(Step 2 passes but mean or variance differs), or"none"(Step 2 fails - composites are not comparable and MGA results would be uninterpretable). Step 2 and Step 3 are also exposed individually viastep2()andstep3().
Closes a longstanding gap: prior releases supported
Plspm.mga(...)but provided no in-engine way to verify the invariance prerequisite MGA assumes. - Step 1 - Configural invariance is guaranteed by construction: the same
1.4.0
Released 2026-06-09.
Five seminr-aligned additions covering one-call reporting, predictive accuracy, structural effect sizes, discriminant validity, and mediation decomposition. All APIs are additive - no existing behaviour or signatures changed - so this is a minor bump.
Added
- Publication-ready summary report via
Plspm.report(include_rho_a=True, include_htmt2=True). Bundles the engine’s individual diagnostics - reliability (Cronbach alpha, rho_A, rho_C, AVE), discriminant validity (HTMT, HTMT2, Fornell-Larcker), structural paths with f² effect sizes and p-values, per-LV R² / adjusted R² / BIC, fit indices (SRMR, d_ULS, GoF), and outer/inner VIF - into a singleReportobject covering the standard PLS-SEM research-report panels expected by Hair, Hult, Ringle and Sarstedt (2022, A Primer on PLS-SEM, 3rd ed.).Report.to_dict()returns every section in one dictionary, ready for JSON export. Pure orchestration: every value comes from an existing lazy-cached method onPlspm, so callingreport()repeatedly is cheap. The two flags trade speed for completeness: turn offinclude_rho_ato skip PLSc; turn offinclude_htmt2to skip the geometric-mean HTMT refinement. - PLSpredict full panel (Shmueli et al. 2019) via the existing
Plspm.predict(...)method.metrics()now reports per-indicator MAPE for PLS and LM (proportion-form,mean(|err / actual|), matching sklearn’s convention) alongside RMSE and MAE, and adds the in-sample counterpartsrmse_pls_in,mae_pls_in,mape_pls_in,rmse_lm_in,mae_lm_in,mape_lm_incomputed from a single fit on the full data. The complete out-of-sample / in-sample comparison is what reviewers expect to see published (Shmueli, Sarstedt, Hair, Cheah, Ting, Vaithilingam and Ringle 2019, Table 6). MAPE rows where the actual value is zero are excluded from MAPE only; all other metrics still see them. Existing columns andsummary()are unchanged. - Cohen’s f² effect size via
Plspm.f_squared(). For each structural-model edgepredictor -> endogenous, refits the endogenous LV’s OLS without the predictor and reportsf² = (R²_full - R²_reduced) / (1 - R²_full)(Cohen 1988; Hair, Hult, Ringle & Sarstedt 2022). ReturnedFSquaredinstance exposes a long-formattable()with conventional effect-size labels (none/small/medium/large, thresholds 0.02 / 0.15 / 0.35) and a squarematrix()mirroring the path matrix. Computed lazily and cached. - Fornell-Larcker discriminant-validity criterion via
Plspm.fornell_larcker(). Returns a square matrix withsqrt(AVE)on the diagonal and inter-construct correlations off-diagonal (Fornell and Larcker 1981).summary()produces a per-LVpassesverdict (Truewhensqrt(AVE)exceeds every absolute off-diagonal entry in its row). Formative (Mode B) and single-indicator LVs receiveNaNon the diagonal because AVE is undefined for them, andsummary()flags them as non-applicable. The modern recommendation (Henseler, Ringle and Sarstedt 2015) is to prefer HTMT for discriminant validity; Fornell-Larcker is provided alongside, not in place of, HTMT. Computed lazily and cached. - Specific indirect effects for mediation analysis via
Plspm.specific_indirect_effects(source, target, through=None)for point estimates andBootstrap.specific_indirect_effects(source, target, through=None, alpha=0.05)for bootstrap percentile CIs. Implements the chain-product procedure of Zhao, Lynch and Chen (2010) and Nitzl, Roldan and Cepeda (2016): each mediation chainsource -> M1 -> ... -> targetcarries an effect equal to the product of its path coefficients, and the per-iteration distribution of that product gives the inferential statistics. Withthrough=Nonethe structural-model DAG is searched for every simple chain fromsourcetotarget; withthroughset, only that single chain is evaluated. Aligns the engine withseminr::specific_effect_significance().
1.3.0
Released 2026-06-09.
Disjoint two-stage higher-order construct (HOC) workflow as a first-class API. The legacy Config.add_higher_order (repeated-indicators / embedded two-stage) stays untouched for backward compatibility, so this is a minor bump.
Added
-
Disjoint two-stage higher-order constructs (HOC) via
Plspm.higher_order(name, first_order, mode, structure, ...). Implements the workflow recommended in Sarstedt, Hair, Cheah, Becker and Ringle (2019) and Hair, Hult, Ringle and Sarstedt (2022, A Primer on PLS-SEM, 3rd ed., Chapter 8). The fittedPlspmbecomes stage 1; its first-order LV scores are appended to the data as indicators of the new second-order construct, and a stage-2Plspmis fit with the HOC in place of its first-order constituents in the structural part of the model. All four canonical HOC types are covered by combining the first-order LV modes (set on the base config) with the HOCmode:- Type I (R-R) - first-order Mode A, HOC Mode A.
- Type II (R-F) - first-order Mode A, HOC Mode B.
- Type III (F-R) - first-order Mode B, HOC Mode A.
- Type IV (F-F) - first-order Mode B, HOC Mode B.
The returned
HigherOrderinstance exposes the stage-1 fit (base()), the stage-2 fit (refit()), the HOC’s measurement model (loadings()), the stage-2 structural path coefficients (path_coefficients()), and a per-first-order summary table. Nested HOCs work by callinghigher_order()again on the stage-2 refit.
1.2.0
Released 2026-06-09.
Three seminr-aligned diagnostics for measurement-error correction, discriminant validity, and structural-equation endogeneity. All three APIs are additive - no existing behaviour or signatures changed - so this is a minor bump.
Added
- Gaussian-copula endogeneity test via
Plspm.copula(endogenous, suspected=None, n_boot=500, seed=42). Park and Gupta (2012) / Hult, Hair, Proksch, Sarstedt, Pinkwart and Ringle (2018) procedure for detecting endogeneity in PLS-SEM structural equations. For the structural equation ofendogenous, each suspected predecessor LV is augmented with a copula termP_k = Φ⁻¹(F_n(X_k))(F_n(x) = rank(x) / (n+1)), the augmented OLS regression is refit on the latent-variable scores, and each copula coefficientγ_kis tested by a non-parametric row bootstrap (sameSE/t/pconvention asLongBootstrap). Each suspected predictor is screened with a Cramér-von Mises normality test against its sample-fitted normal;summary()marks normal predictors ascopula not admissible (normal)because under normality the copula term degenerates and the test cannot tell endogeneity from a Gaussian regressor. Returns per-predictorgamma,boot_se,t,p_value,cvm_p_nonnormal, the endogeneity-correctedaugmented_paths, and a verdict column. - HTMT2 via
Plspm.htmt2(). Geometric-mean refinement of the Heterotrait-Monotrait Ratio of Correlations (Roemer, Schuberth and Henseler 2021). Replaces the two arithmetic means in the original Henseler/Ringle/Sarstedt 2015 HTMT with geometric means (exp(mean(log(·)))), removing the bias HTMT shows when indicator loadings within a block are unequal. HTMT2 is consistent under the tau-equivalent / congeneric measurement model. Same API surface asHTMT-matrix()returns the symmetric matrix andpairs()returns the long-format view. Pairs involving a single-indicator construct or any zero indicator correlation are returned asNaN(the geometric mean is undefined in those cases). The same conservative discriminant-validity thresholds apply (HTMT2 < 0.85/< 0.90). - Consistent PLS (PLSc) via
Plspm.plsc(). Applies the Dijkstra and Henseler (2015) bias correction for reflective (Mode A) measurement: each construct receives a closed-formrho_Areliability(w'w)² · w'Sw / w'(ww' − diag) w, off-diagonal construct correlations are dis-attenuated bysqrt(rho_A_i · rho_A_j), and path coefficients are re-estimated by OLS on the adjusted correlation matrix. CorrectedR², adjustedR², and outer loadings (λ_k = w_k · sqrt(rho_A) / (w'w)) are returned side by side with the composite-model originals. Formative (Mode B) and single-indicator constructs receiverho_A = 1by convention and are not adjusted. Aligns withseminr::PLSc().
1.1.0
Released 2026-06-09.
Two seminr-aligned outer-model diagnostics. Both APIs are additive - no existing behaviour or signatures changed - so this is a minor bump.
Added
- Variance Inflation Factor (VIF) diagnostics via
Plspm.vif(). Two views:items()returns per-indicator VIF within each construct block (collinearity diagnostic primarily for Mode B / formative blocks; for each indicatorx_jin a block with two or more indicators,x_jis regressed on the remaining indicators andVIF_j = 1 / (1 - R²_j)), andinner()returns per-predictor VIF for each endogenous LV (structural collinearity among antecedents - each predictor’s score is regressed on the other predictors’ scores). Single-indicator blocks and single-predictor endogenous LVs are omitted (VIF undefined or trivially1). Aligns the engine withseminr::vif_items(). - Confirmatory Tetrad Analysis (CTA-PLS) via
Plspm.cta(n_boot=500, alpha=0.05, seed=42). Outer-model diagnostic that tests whether reflective (Mode A) specification is consistent with the data, per block of four or more indicators, using Bollen and Ting’s (1993) vanishing-tetrad theorem and the bootstrap procedure of Gudergan, Ringle, Wende and Will (2008). One canonical tetrad per indicator 4-tuple givesC(p, 4)non-redundant tetrads per block; each is bootstrapped to obtain a two-sided percentile p-value underH₀: τ = 0(after centering the bootstrap distribution on zero), then reduced with a within-block Holm step-down correction atalpha.tetrads()returns the per-tetrad table;summary()returns the per-block verdict ("reflective supported"vs"reflective rejected"). Mode B blocks and reflective blocks with fewer than four indicators are omitted.
1.0.2
Released 2026-06-01.
Test-suite hardening release. No API changes, no runtime behaviour changes - 1.0.2 is binary-identical to 1.0.1 at runtime.
Added
- Scheme-equivalence regression test (
tests/test_scheme_equivalence_two_lv.py). On any two-LV model each LV has exactly one neighbour, so the inner-weighting update degenerates and PATH, CENTROID, FACTORIAL, PCA, and NEWTON must produce identical path coefficients, weights, loadings, and R². The test locks this invariant down to< 1e-6. - Redundancy-analysis regression test (
tests/test_redundancy_analysis_mode_b.py). A Mode B (formative) driver block predicting a single-item global rating LV. Asserts path recovery is positive and within a sampling band across seeds, R² lies in the expected attenuated range, and the single-indicator loading is exactly1.0. Also parametrized across inner schemes for the degenerate two-LV case. - Path-recovery regression test (
tests/test_path_recovery_synthetic.py). Three-LV mediation chainX → M → Ywith known structural coefficients. Asserts the engine recovers direct paths, indirect / direct / total effects, and the population R² onYwithin sampling tolerance over multiple seeds.
Changed
- Internal docstring and comment phrasing in
openpls/config.py,openpls/fit.py,tests/test_fit.py, andtests/test_sign_convention.pynow reference the underlying methodological convention (Henseler et al. 2014 §5.3, Hair et al., Wold) directly. No code behaviour change.
1.0.1
Released 2026-06-01.
Two SmartPLS-parity fixes discovered while validating 1.0.0 against 14 reference cases. No API changes.
Fixed
- Per-LV sign vote in
_MetricWeights.calculate(). The previous implementation computednp.sign(cor * odm)first and applied the membership mask after. Becausenp.sign(0) == 0butmath.copysign(1.0, 0) == +1.0for the per-cell variant, every non-belonging indicator contributed a phantom+1to the LV’s sign vote. A small LV (e.g. 3 indicators) embedded in a much larger model could therefore be out-voted by the phantom contributions of the larger LV, leaving it on the wrong sign even when every one of its own indicators correlated negatively with the latent direction. The sign is now computed first and multiplied by the membership mask, so non-belonging cells contribute0rather than+1. Empirical impact: the OI validation cases now match SmartPLS onOrg_Ident → AC_Love(β was+0.41versus SmartPLS−0.41). - Saturated-model SRMR and d_ULS exclude within-LV pairs for Mode B (formative) constructs. The implied indicator-correlation matrix
Σ̂ = Λ Φ Λᵀonly constrains common-factor (Mode A) measurement. Mode B indicators are exogenous causes of the composite, so their pairwise correlation is empirical, not implied byΛᵢ Λⱼ. Including those pairs in the SRMR and d_ULS sums inflated both metrics purely as a measurement-model artifact (Henseler et al. 2014 §5.3, SmartPLS convention). Fit now builds an inclusion mask that excludes within-Mode-B-LV blocks and aggregates over the kept pairs only. Models without Mode B LVs are unaffected. Empirical impact: the Corporate Reputation Advanced d_ULS gap closes from+0.5104to−0.0004.
Added
- Regression test
tests/test_sign_convention.pyconstructing a 14-indicator LV alongside a 3-indicator LV whose indicators are all inverted; pins the sign-vote behaviour against the old phantom-vote bug. - Regression test
tests/test_fit.py::test_mode_b_within_lv_pairs_excluded_from_fitasserting that the within-Mode-B residual block is masked out of both SRMR and d_ULS sums by exact arithmetic identity.
1.0.0
Released 2026-06-01.
First stable release. The API surface (Plspm, Config, Mode, Scheme, IPMA, PLSPredict, Moderation, FIMIX) now follows semver: breaking changes require a major version bump.
Changed
- Namespace renamed
plspm→openpls. All imports change shape:from plspm import Plspmbecomesfrom openpls import Plspm,import plspm.config as cbecomesimport openpls.config as c, and similarly foropenpls.mode,openpls.scheme,openpls.mga,openpls.fimix,openpls.ipma,openpls.moderation,openpls.predict,openpls.long_bootstrap. The distribution name on PyPI (openpls-engine) is unchanged. Consumers upgrading from0.7.xmust rewrite their imports. - Column-wise standardization. Indicators are now standardized per column with Bessel-corrected variance (ddof=1), matching SmartPLS 4 conventions. The previous pooled-stack standardization is gone. This shifts numerical alignment closer to SmartPLS 4 for mixed-scale indicator blocks. Path coefficients and quality criteria can move by a few percent on existing models.
setup.pyshim removed. Project metadata is fully driven by PEP 621pyproject.toml. Source installs should use a modernpip(pip install -e .continues to work).
Fixed
- LV name may equal an indicator column name.
add_lv()no longer rejects configurations where a latent variable shares its name with one of its manifest variables (the ECSICUSCOsingle-item LV pattern). Internal LV and MV namespaces are distinct, so the collision was a false positive.
0.7.0a3
Released 2026-05-30.
Second feature release. Ships four advanced PLS-SEM analyses (IPMA, PLSpredict, two-stage moderation, FIMIX-PLS) and two additional inner-weighting schemes (Newton/BFGS and Lohmöller’s PCA), filling the gap between the original plspm-python API and mainstream commercial PLS-SEM tools.
Added
Scheme.PCA: Lohmöller’s PCA inner-weighting scheme (Lohmöller 1989, Section 2.4.2). For each LV, the inner weights are the components of the first principal direction of its neighbor-score matrix, sign-flipped to correlate positively with the LV. Treats neighbor weights as a joint multivariate direction rather than as pairwise quantities.Scheme.NEWTON: quasi-Newton (BFGS) inner-weighting scheme. For each latent variable, jointly fits inner weights over all neighbors (predecessors and successors together) via BFGS minimization of a least-squares objective, in contrast to the classical PATH scheme, which mixes OLS coefficients for predecessors with bare correlations for successors. Initialized from the analytical OLS solution; usesscipy.optimizefor the second-order Hessian-secant update.openpls.fimix.FIMIX: Finite Mixture PLS (Hahn et al. 2002) for latent class segmentation. EM algorithm with multiple random restarts detects K subgroups sharing the measurement model but with distinct structural paths. Reports per-class path coefficients, posterior memberships, hard assignments, and information criteria (AIC, AIC3, AIC4, BIC, CAIC, MDL5, normalized entropy EN). Exposed asPlspm.fimix(n_classes).openpls.ipma.IPMA: Importance-Performance Map Analysis. For a chosen target endogenous LV, returns each predecessor’s importance (total effect) and performance (mean of 0-100-rescaled LV score), plus an indicator-level breakdown with rescaled-mean performance and normalized weights. Exposed asPlspm.ipma(target).openpls.moderation.Moderation: two-stage moderation (Henseler and Chin 2010). Fits a base model, multiplies the standardized LV scores for predictor and moderator into a product column, and refits with that product as a single-indicator construct pointing at the target. Exposesbase(),refit(), andinteraction_effect().openpls.predict.PLSPredict: PLSpredict via k-fold cross-validation. Per-indicator RMSE/MAE for PLS and a linear-regression benchmark, plus Q squared predict against the indicator-average baseline (Shmueli et al. 2019). Exposed asPlspm.predict(k=10, repeats=1, seed=42);summary()returns the per-indicator PLS-vs-LM verdict.
0.7.0a2
Released 2026-05-30.
First release published to PyPI. Identical code to 0.7.0a1; bumped only to validate the trusted-publisher pipeline end to end. The previous v0.7.0a1 GitHub release stays available as a download but was never uploaded to PyPI.
0.7.0a1
Released 2026-05-30.
All planned ports from the OpenPLS web app are now in. This is the first feature-complete pre-release.
Added
openpls.long_bootstrap.LongBootstrap: serial bootstrap with progress callback, sign-flipping, BCa percentile CIs, normal-approximation p-values, and a configurable success-rate floor. Suited for long-running, progress-streaming workloads.openpls.mga.MGAandopenpls.mga.GroupSpec: Multi-Group Analysis via Henseler permutation, with categorical and numeric-range group definitions, pairwise comparisons across 2+ groups, two-sided permutation p-values with Phipson-Smyth add-one smoothing.Plspm(..., missing_strategy="mean"): mean replacement for NaN cells in indicator columns. Default"casewise"preserves upstream behavior.openpls.q_squared.QSquared: Stone-Geisser Q squared via blindfolding with configurable omission distance D. Exposed asPlspm.q_squared().openpls.htmt.HTMT: Heterotrait-Monotrait ratio of correlations.openpls.fit.ModelFit: SRMR (Standardized Root Mean Square Residual) and d_ULS (unweighted least-squares discrepancy).- BIC for endogenous LVs in
openpls.inner_summary. - Listwise-deletion fallback for Cronbach alpha and Dijkstra-Henseler rho when an LV’s indicator block contains NaN.
openpls.__version__reports the installed package version at runtime.
Changed
- Project metadata moved from
setup.pyto PEP 621pyproject.toml. - Lint pipeline (ruff) and test pipeline (pytest) run on Python 3.10 through 3.13 in CI.
0.6.0a1
Released 2026-05-30.
Initial OpenPLS rebrand of the plspm-python 0.5.7 baseline.
Added
- Forked
plspm-python0.5.7 with attribution preserved. pyproject.toml, ruff config, GitHub Actions CI matrix (Py 3.10 to 3.13).