dspin 1.4.2__tar.gz → 1.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dspin-1.4.2/dspin.egg-info → dspin-1.5.0}/PKG-INFO +1 -1
- {dspin-1.4.2 → dspin-1.5.0}/dspin/compute.py +266 -68
- {dspin-1.4.2 → dspin-1.5.0/dspin.egg-info}/PKG-INFO +1 -1
- {dspin-1.4.2 → dspin-1.5.0}/setup.py +1 -1
- {dspin-1.4.2 → dspin-1.5.0}/LICENSE +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/README.md +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/__pycache__/__init__.cpython-310.pyc +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/__pycache__/__init__.cpython-37.pyc +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/__pycache__/compute.cpython-310.pyc +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/__pycache__/compute.cpython-37.pyc +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/__pycache__/dspin_abstract.cpython-310.pyc +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/__pycache__/plot.cpython-310.pyc +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/__pycache__/plotting.cpython-37.pyc +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/dspin/__init__.py +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/dspin/annotate.py +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/dspin/dspin.py +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/dspin/plot.py +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/dspin.egg-info/SOURCES.txt +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/dspin.egg-info/dependency_links.txt +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/dspin.egg-info/requires.txt +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/dspin.egg-info/top_level.txt +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/requirements.txt +0 -0
- {dspin-1.4.2 → dspin-1.5.0}/setup.cfg +0 -0
|
@@ -21,6 +21,10 @@ from typing import Tuple, List, Callable, Any, Dict
|
|
|
21
21
|
import warnings
|
|
22
22
|
from scipy.sparse import issparse
|
|
23
23
|
from joblib import Parallel, delayed, parallel_backend
|
|
24
|
+
from sklearn.cluster import AgglomerativeClustering
|
|
25
|
+
import leidenalg as la
|
|
26
|
+
import igraph as ig
|
|
27
|
+
import networkx as nx
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
def category_balance_number(
|
|
@@ -70,11 +74,6 @@ def category_balance_number(
|
|
|
70
74
|
return sampling_number
|
|
71
75
|
|
|
72
76
|
|
|
73
|
-
from sklearn.cluster import AgglomerativeClustering
|
|
74
|
-
import leidenalg as la
|
|
75
|
-
import igraph as ig
|
|
76
|
-
import networkx as nx
|
|
77
|
-
|
|
78
77
|
def summary_components(all_components: np.array,
|
|
79
78
|
num_spin: int,
|
|
80
79
|
summary_method: str = 'kmeans',
|
|
@@ -125,8 +124,6 @@ def summary_components(all_components: np.array,
|
|
|
125
124
|
# Determine gene cluster assignments based on the maximum component values.
|
|
126
125
|
gene_groups_ind.append(np.argmax(components_kmeans, axis=0) == ii)
|
|
127
126
|
|
|
128
|
-
|
|
129
|
-
|
|
130
127
|
sc.set_figure_params(figsize=(8, 4))
|
|
131
128
|
|
|
132
129
|
plt.subplot(1, 2, 1)
|
|
@@ -569,6 +566,7 @@ def para_moments_numpy(j_mat: np.array, h_vec: np.array) -> Tuple[np.array, np.a
|
|
|
569
566
|
|
|
570
567
|
return corr_para, mean_para
|
|
571
568
|
|
|
569
|
+
|
|
572
570
|
@numba.njit(fastmath=True, cache=True)
|
|
573
571
|
def para_moments(j_mat: np.ndarray,
|
|
574
572
|
h_vec: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
|
|
@@ -708,8 +706,7 @@ def pseudol_gradient(cur_j: np.ndarray,
|
|
|
708
706
|
def samp_moments(j_mat: np.ndarray,
|
|
709
707
|
h_vec: np.ndarray,
|
|
710
708
|
sample_size: int,
|
|
711
|
-
mixing_time: int,
|
|
712
|
-
samp_gap: int) -> Tuple[np.ndarray, np.ndarray]:
|
|
709
|
+
mixing_time: int) -> Tuple[np.ndarray, np.ndarray]:
|
|
713
710
|
"""
|
|
714
711
|
Sample moments for the Markov Chain Monte Carlo (MCMC).
|
|
715
712
|
|
|
@@ -723,8 +720,6 @@ def samp_moments(j_mat: np.ndarray,
|
|
|
723
720
|
Size of the sample.
|
|
724
721
|
mixing_time : int
|
|
725
722
|
Mixing time for the MCMC.
|
|
726
|
-
samp_gap : int
|
|
727
|
-
Gap between samples.
|
|
728
723
|
|
|
729
724
|
Returns
|
|
730
725
|
-------
|
|
@@ -732,73 +727,241 @@ def samp_moments(j_mat: np.ndarray,
|
|
|
732
727
|
The correlation parameter.
|
|
733
728
|
The mean parameter.
|
|
734
729
|
"""
|
|
735
|
-
|
|
730
|
+
sample_size = int(sample_size)
|
|
731
|
+
mixing_time = int(mixing_time)
|
|
732
|
+
|
|
736
733
|
num_spin = j_mat.shape[0]
|
|
737
|
-
rec_corr = np.zeros((num_spin, num_spin))
|
|
738
|
-
rec_mean = np.zeros(num_spin)
|
|
739
|
-
beta = 1
|
|
740
|
-
batch_count = 1
|
|
741
|
-
rec_sample = np.empty((num_spin, min(per_batch, int(sample_size))))
|
|
742
|
-
cur_spin = (np.random.randint(0, 3, (num_spin, 1)) - 1).astype(np.float64)
|
|
743
|
-
tot_sampling = int(
|
|
744
|
-
mixing_time + sample_size * samp_gap - mixing_time % samp_gap)
|
|
734
|
+
rec_corr = np.zeros((num_spin, num_spin), dtype=np.float64)
|
|
735
|
+
rec_mean = np.zeros(num_spin, dtype=np.float64)
|
|
736
|
+
beta = 1.0
|
|
745
737
|
|
|
746
|
-
|
|
747
|
-
|
|
738
|
+
# Cast & make contiguous (Numba-safe)
|
|
739
|
+
j_mat = np.ascontiguousarray(j_mat.astype(np.float64))
|
|
740
|
+
h_vec = np.ascontiguousarray(h_vec.astype(np.float64)).reshape(-1)
|
|
741
|
+
|
|
742
|
+
# Spins in {-1,0,1}
|
|
743
|
+
cur_spin = np.sign(h_vec).astype(np.float64)
|
|
744
|
+
|
|
745
|
+
# Local field f = h + J @ s (update incrementally on changes)
|
|
746
|
+
f_vec = h_vec + j_mat.dot(cur_spin)
|
|
747
|
+
|
|
748
|
+
# Sampling schedule
|
|
749
|
+
tot_sampling = sample_size + mixing_time
|
|
750
|
+
|
|
751
|
+
# Pre-generate randomness (one uniform per site update)
|
|
748
752
|
rand_prob = np.random.rand(tot_sampling)
|
|
749
753
|
|
|
750
|
-
#
|
|
754
|
+
# Lazy accumulation buffers
|
|
755
|
+
last_outer = np.zeros((num_spin, num_spin), dtype=np.float64) # current s s^T
|
|
756
|
+
have_last_outer = False
|
|
757
|
+
recording_started = False
|
|
758
|
+
weight = 0 # how many identical samples to add for current last_outer
|
|
759
|
+
|
|
760
|
+
# MCMC with sweep updates + heat-bath conditionals
|
|
751
761
|
for ii in range(tot_sampling):
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
762
|
+
# sweep index (no random site index)
|
|
763
|
+
cur_ind = ii % num_spin
|
|
764
|
+
|
|
765
|
+
# current spin and local field excluding self-term
|
|
766
|
+
s_i = cur_spin[cur_ind]
|
|
767
|
+
Jii = j_mat[cur_ind, cur_ind]
|
|
768
|
+
hstar = f_vec[cur_ind] - Jii * s_i
|
|
769
|
+
|
|
770
|
+
# heat-bath weights for k in {+1, 0, -1}:
|
|
771
|
+
# log-weights: a = beta*( hstar + 0.5*Jii ), b = 0, c = beta*( -hstar + 0.5*Jii )
|
|
772
|
+
a = beta * (hstar + Jii)
|
|
773
|
+
b = 0.0
|
|
774
|
+
c = beta * (-hstar + Jii)
|
|
775
|
+
m = max(a, b, c)
|
|
776
|
+
pa = np.exp(a - m)
|
|
777
|
+
pb = np.exp(b - m) # == exp(-m)
|
|
778
|
+
pc = np.exp(c - m)
|
|
779
|
+
Z = pa + pb + pc
|
|
780
|
+
|
|
781
|
+
# sample new spin
|
|
782
|
+
u = rand_prob[ii]
|
|
783
|
+
thresh_a = pa / Z
|
|
784
|
+
thresh_ab = (pa + pb) / Z
|
|
785
|
+
if u < thresh_a:
|
|
786
|
+
new_spin = 1.0
|
|
787
|
+
elif u < thresh_ab:
|
|
788
|
+
new_spin = 0.0
|
|
765
789
|
else:
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
790
|
+
new_spin = - 1.0
|
|
791
|
+
|
|
792
|
+
# if spin changed, update cur_spin and cached field
|
|
793
|
+
changed = (new_spin != s_i)
|
|
794
|
+
if changed:
|
|
795
|
+
delta_s = new_spin - s_i
|
|
796
|
+
cur_spin[cur_ind] = new_spin
|
|
797
|
+
# incremental local-field update: f_k += J[k,i] * delta_s
|
|
798
|
+
for k in range(num_spin):
|
|
799
|
+
f_vec[k] += j_mat[k, cur_ind] * delta_s
|
|
800
|
+
|
|
801
|
+
# If we're recording and have accumulated weight, flush rec_corr BEFORE changing last_outer
|
|
802
|
+
if recording_started and weight > 0 and have_last_outer:
|
|
803
|
+
for k in range(num_spin):
|
|
804
|
+
row = rec_corr[k]
|
|
805
|
+
lo_row = last_outer[k]
|
|
806
|
+
for l in range(num_spin):
|
|
807
|
+
row[l] += weight * lo_row[l]
|
|
808
|
+
weight = 0
|
|
809
|
+
|
|
810
|
+
# Update last_outer incrementally if it exists
|
|
811
|
+
if recording_started and have_last_outer:
|
|
812
|
+
d = delta_s
|
|
813
|
+
i = cur_ind
|
|
814
|
+
# s's' = s s^T + d (e_i s'^T + s' e_i^T) - d^2 e_i e_i^T (uses updated cur_spin)
|
|
815
|
+
for j in range(num_spin):
|
|
816
|
+
last_outer[i, j] += d * cur_spin[j]
|
|
817
|
+
for j in range(num_spin):
|
|
818
|
+
last_outer[j, i] += d * cur_spin[j]
|
|
819
|
+
last_outer[i, i] -= d * d
|
|
820
|
+
|
|
821
|
+
# Record sample on schedule
|
|
822
|
+
if ii >= mixing_time:
|
|
823
|
+
# mean: O(N)
|
|
824
|
+
for k in range(num_spin):
|
|
825
|
+
rec_mean[k] += cur_spin[k]
|
|
826
|
+
|
|
827
|
+
# initialize last_outer once at the first record
|
|
828
|
+
if not recording_started:
|
|
829
|
+
for k in range(num_spin):
|
|
830
|
+
sk = cur_spin[k]
|
|
831
|
+
row = last_outer[k]
|
|
832
|
+
for l in range(num_spin):
|
|
833
|
+
row[l] = sk * cur_spin[l]
|
|
834
|
+
have_last_outer = True
|
|
835
|
+
recording_started = True
|
|
836
|
+
|
|
837
|
+
# lazily count how many times to add current outer
|
|
838
|
+
weight += 1
|
|
839
|
+
|
|
840
|
+
# Flush any remaining weight after the loop
|
|
841
|
+
if recording_started and weight > 0 and have_last_outer:
|
|
842
|
+
for k in range(num_spin):
|
|
843
|
+
row = rec_corr[k]
|
|
844
|
+
lo_row = last_outer[k]
|
|
845
|
+
for l in range(num_spin):
|
|
846
|
+
row[l] += weight * lo_row[l]
|
|
795
847
|
|
|
796
848
|
corr_para = rec_corr / sample_size
|
|
797
849
|
mean_para = rec_mean / sample_size
|
|
798
|
-
|
|
850
|
+
|
|
799
851
|
return corr_para, mean_para
|
|
800
852
|
|
|
801
853
|
|
|
854
|
+
@numba.njit()
|
|
855
|
+
def samp_mcmc_states(j_mat: np.ndarray,
|
|
856
|
+
h_vec: np.ndarray,
|
|
857
|
+
sample_size: int,
|
|
858
|
+
mixing_time: int,
|
|
859
|
+
samp_gap: int) -> np.ndarray:
|
|
860
|
+
"""
|
|
861
|
+
Sample states for the Markov Chain Monte Carlo (MCMC).
|
|
862
|
+
|
|
863
|
+
Parameters
|
|
864
|
+
----------
|
|
865
|
+
j_mat : np.ndarray
|
|
866
|
+
Interaction matrix.
|
|
867
|
+
h_vec : np.ndarray
|
|
868
|
+
External field vector.
|
|
869
|
+
sample_size : int
|
|
870
|
+
Size of the sample.
|
|
871
|
+
mixing_time : int
|
|
872
|
+
Mixing time for the MCMC.
|
|
873
|
+
samp_gap : int
|
|
874
|
+
Gap between samples.
|
|
875
|
+
|
|
876
|
+
Returns
|
|
877
|
+
-------
|
|
878
|
+
np.ndarray
|
|
879
|
+
The sampled states.
|
|
880
|
+
"""
|
|
881
|
+
sample_size = int(sample_size)
|
|
882
|
+
mixing_time = int(mixing_time)
|
|
883
|
+
samp_gap = int(samp_gap)
|
|
884
|
+
|
|
885
|
+
num_spin = j_mat.shape[0]
|
|
886
|
+
|
|
887
|
+
beta = 1.0
|
|
888
|
+
batch_count = 1
|
|
889
|
+
rec_sample = np.empty((num_spin, int(sample_size)), dtype=np.float64)
|
|
890
|
+
|
|
891
|
+
# Cast & make contiguous (Numba-safe)
|
|
892
|
+
j_mat = np.ascontiguousarray(j_mat.astype(np.float64))
|
|
893
|
+
# Accept both (n,) and (n,1) h_vec; flatten to 1D
|
|
894
|
+
h_vec = h_vec.reshape(h_vec.size)
|
|
895
|
+
h_vec = np.ascontiguousarray(h_vec.astype(np.float64))
|
|
896
|
+
|
|
897
|
+
# Spins in {-1,0,1}
|
|
898
|
+
cur_spin = (np.random.randint(0, 3, num_spin) - 1).astype(np.float64)
|
|
899
|
+
|
|
900
|
+
# Local field f = h + J @ s (update incrementally on changes)
|
|
901
|
+
f_vec = h_vec + j_mat.dot(cur_spin)
|
|
902
|
+
|
|
903
|
+
# Sampling schedule (avoid modulo inside loop)
|
|
904
|
+
rem = mixing_time % samp_gap
|
|
905
|
+
first_sample = mixing_time if rem == 0 else (mixing_time + (samp_gap - rem))
|
|
906
|
+
last_sample = first_sample + (sample_size - 1) * samp_gap
|
|
907
|
+
tot_sampling = last_sample + 1
|
|
908
|
+
next_sample = first_sample
|
|
909
|
+
|
|
910
|
+
# Pre-generate randomness: one uniform per single-site update
|
|
911
|
+
rand_prob = np.random.rand(tot_sampling)
|
|
912
|
+
|
|
913
|
+
# MCMC (Gibbs) with deterministic sweep order
|
|
914
|
+
for ii in range(tot_sampling):
|
|
915
|
+
cur_ind = ii % num_spin
|
|
916
|
+
|
|
917
|
+
# ---- Compute conditional for s_i given s_-i (PRE-UPDATE neighborhood) ----
|
|
918
|
+
s_i = cur_spin[cur_ind]
|
|
919
|
+
Jii = j_mat[cur_ind, cur_ind]
|
|
920
|
+
# h*_i = h_i + sum_{j!=i} J_ij s_j = f_i - J_ii * s_i (pre-update)
|
|
921
|
+
hstar = f_vec[cur_ind] - Jii * s_i
|
|
922
|
+
|
|
923
|
+
# Unnormalized log-weights for k in {+1, 0, -1}
|
|
924
|
+
# Matches the enumerator convention (diagonal contributes +J_ii*k^2 here)
|
|
925
|
+
a = beta * (hstar + Jii) # log w(+1)
|
|
926
|
+
b = 0.0 # log w(0)
|
|
927
|
+
c = beta * (-hstar + Jii) # log w(-1)
|
|
928
|
+
|
|
929
|
+
# Stable normalization via max-trick
|
|
930
|
+
m = max(a, b, c)
|
|
931
|
+
pa = np.exp(a - m)
|
|
932
|
+
pb = np.exp(b - m)
|
|
933
|
+
pc = np.exp(c - m)
|
|
934
|
+
Z = pa + pb + pc
|
|
935
|
+
|
|
936
|
+
# Sample new spin from the conditional (heat-bath)
|
|
937
|
+
u = rand_prob[ii]
|
|
938
|
+
t1 = pa / Z
|
|
939
|
+
t2 = (pa + pb) / Z
|
|
940
|
+
if u < t1:
|
|
941
|
+
new_spin = 1.0
|
|
942
|
+
elif u < t2:
|
|
943
|
+
new_spin = 0.0
|
|
944
|
+
else:
|
|
945
|
+
new_spin = -1.0
|
|
946
|
+
|
|
947
|
+
# If changed, update spin and cached local field
|
|
948
|
+
if new_spin != s_i:
|
|
949
|
+
delta_s = new_spin - s_i
|
|
950
|
+
cur_spin[cur_ind] = new_spin
|
|
951
|
+
# Incremental local-field update: f_k += J[k, i] * delta_s
|
|
952
|
+
for k in range(num_spin):
|
|
953
|
+
f_vec[k] += j_mat[k, cur_ind] * delta_s
|
|
954
|
+
|
|
955
|
+
# Record sample on schedule
|
|
956
|
+
if ii == next_sample:
|
|
957
|
+
for k in range(num_spin):
|
|
958
|
+
rec_sample[k, batch_count - 1] = cur_spin[k]
|
|
959
|
+
batch_count += 1
|
|
960
|
+
next_sample += samp_gap
|
|
961
|
+
|
|
962
|
+
return rec_sample
|
|
963
|
+
|
|
964
|
+
|
|
802
965
|
def _gradient_one_round(kk: int,
|
|
803
966
|
cur_j: np.ndarray,
|
|
804
967
|
cur_h: np.ndarray,
|
|
@@ -814,7 +977,7 @@ def _gradient_one_round(kk: int,
|
|
|
814
977
|
corr_para, mean_para = para_moments(cur_j, cur_h[:, kk])
|
|
815
978
|
elif method == 'mcmc_maximum_likelihood':
|
|
816
979
|
corr_para, mean_para = samp_moments(
|
|
817
|
-
cur_j, cur_h[:, kk], train_dat['mcmc_samplingsz'], train_dat['mcmc_samplingmix']
|
|
980
|
+
cur_j, cur_h[:, kk], train_dat['mcmc_samplingsz'], train_dat['mcmc_samplingmix'])
|
|
818
981
|
j_grad = corr_para - raw_data_k[0]
|
|
819
982
|
h_grad = mean_para - raw_data_k[1].flatten()
|
|
820
983
|
|
|
@@ -985,6 +1148,7 @@ def apply_regularization(rec_jgrad: np.ndarray,
|
|
|
985
1148
|
|
|
986
1149
|
if 'lambda_l2_h_rela_prior' in train_dat:
|
|
987
1150
|
perturb_matrix = train_dat['perturb_matrix']
|
|
1151
|
+
rec_hgrad = average_batch_control(rec_hgrad, if_control, batch_index)
|
|
988
1152
|
rec_hgrad += train_dat['lambda_l2_h_rela_prior'] * (h_rela - perturb_matrix)
|
|
989
1153
|
|
|
990
1154
|
if 'lambda_l1_h_rela' in train_dat:
|
|
@@ -1421,7 +1585,7 @@ def compute_relative_responses(cur_h: np.ndarray,
|
|
|
1421
1585
|
batch_samples_idx = np.where(batch_index == current_batch)[0]
|
|
1422
1586
|
|
|
1423
1587
|
if np.any(if_control[batch_samples_idx]):
|
|
1424
|
-
batch_controls_idx = batch_samples_idx[if_control[batch_samples_idx]]
|
|
1588
|
+
batch_controls_idx = batch_samples_idx[np.where(if_control[batch_samples_idx])[0]]
|
|
1425
1589
|
batch_controls_mean = np.mean(cur_h[:, batch_controls_idx], axis=1)
|
|
1426
1590
|
else:
|
|
1427
1591
|
batch_controls_mean = all_controls_mean
|
|
@@ -1432,6 +1596,40 @@ def compute_relative_responses(cur_h: np.ndarray,
|
|
|
1432
1596
|
return relative_h
|
|
1433
1597
|
|
|
1434
1598
|
|
|
1599
|
+
def average_batch_control(hgrad_raw: np.ndarray,
|
|
1600
|
+
if_control: np.ndarray,
|
|
1601
|
+
batch_index: np.ndarray) -> np.ndarray:
|
|
1602
|
+
"""
|
|
1603
|
+
Assign the gradient of control samples as the average gradient of the samples in the same batch.
|
|
1604
|
+
|
|
1605
|
+
Parameters
|
|
1606
|
+
----------
|
|
1607
|
+
hgrad : np.ndarray
|
|
1608
|
+
The gradient of the h matrix.
|
|
1609
|
+
if_control : np.ndarray
|
|
1610
|
+
A boolean array indicating which samples are control samples.
|
|
1611
|
+
batch_index : np.ndarray
|
|
1612
|
+
An array indicating the batch assignment for each sample.
|
|
1613
|
+
"""
|
|
1614
|
+
|
|
1615
|
+
hgrad = hgrad_raw.copy()
|
|
1616
|
+
|
|
1617
|
+
unique_batches = np.unique(batch_index)
|
|
1618
|
+
num_batches = len(unique_batches)
|
|
1619
|
+
|
|
1620
|
+
for current_batch in unique_batches:
|
|
1621
|
+
batch_samples_idx = np.where(batch_index == current_batch)[0]
|
|
1622
|
+
|
|
1623
|
+
if np.any(if_control[batch_samples_idx]):
|
|
1624
|
+
if np.any(if_control[batch_samples_idx]):
|
|
1625
|
+
batch_controls_idx = batch_samples_idx[np.where(if_control[batch_samples_idx])[0]]
|
|
1626
|
+
batch_mean = np.mean(hgrad_raw[:, batch_samples_idx], axis=1)
|
|
1627
|
+
|
|
1628
|
+
hgrad[:, batch_controls_idx] = batch_mean[:, np.newaxis]
|
|
1629
|
+
|
|
1630
|
+
return hgrad
|
|
1631
|
+
|
|
1632
|
+
|
|
1435
1633
|
def select_representative_sample(raw_data: List[Tuple[np.ndarray, np.ndarray]],
|
|
1436
1634
|
num_select: int) -> List[int]:
|
|
1437
1635
|
"""
|
|
@@ -21,7 +21,7 @@ install_requires = [
|
|
|
21
21
|
# ]
|
|
22
22
|
|
|
23
23
|
# Managing your version (adjust accordingly)
|
|
24
|
-
version = "1.
|
|
24
|
+
version = "1.5.0" # You can manage versioning in a more sophisticated way if needed
|
|
25
25
|
|
|
26
26
|
# Long description (usually a README file)
|
|
27
27
|
readme = open("README_PyPI.md").read() # Adjust the file name if necessary
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|