Project: s41467-025-56173-6 | Function: weightnoisyor (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Core weighted noisy-OR probability aggregation function that calculates bag probability from instance probabilities using weighted rank-based distributions. This function implements the key mathematical innovation of pum6a by computing weighted combinations of instance predictions through dual normal distributions and rank-based weighting.

**KEY TERMS:** {
  "pij": "instance probability f(x_j)",
  "noisyor": "bag probability P(Y_B=1)",
  "w": "weights w_j computed from rank distributions",
  "ranks": "rank-based weighting scheme",
  "rv1, rv2": "dual normal distributions N_0 and N_1"
}

**CONTEXT CODE:**     attention = nn.Sequential(
        nn.Linear(L, D),
        nn.Tanh(),
        nn.Linear(D, K)
    )

    return attention

def build_classifier(input: Optional[int]=500):

    r'''
    Instance method for building classifier module according

        Args:
            input (int):  attention module input nodes

        Return:
            classifier (torch.nn.Sequential): classifier module
    '''


    classifier = nn.Sequential(
        nn.Linear(input, 1),
        nn.Sigmoid()
    )

    return classifier


def build_logistic(device: Optional[str]='cuda'):

    '''

    Instance method for building logistic module

        Args:
            device (str): whether to use cuda for calculation

        Return:
            A (torch.nn.Parameter): weight parameter of logistic module
            B (torch.nn.Parameter): bias parameter of logistic module

    '''

    A = torch.nn.Parameter(torch.tensor(torch.rand(1, device=device)), requires_grad=True)
    A.grad = torch.tensor(torch.rand(1, device=device))
    B = torch.nn.Parameter(torch.tensor(torch.rand(1, device=device)), requires_grad=True)

    return A, B

def weightnoisyor(pij: Optional[list] = None,
                  device: Optional[str] = 'cuda',
                  mu1: Optional[int] = 0,
                  mu2: Optional[int] = 1,
                  sigma1: Optional[int] = 0.1,
                  sigma2: Optional[int] = 0.1,
                  ):
    # MASKED: Core weighted noisy-OR probability aggregation function that calculates bag probability from instance probabilities using weighted rank-based distributions. This function implements the key mathematical innovation of pum6a by computing weighted combinations of instance predictions through dual normal distributions and rank-based weighting.
    raise NotImplementedError("This function is masked for testing purposes.")


def log_diverse_density(pi, y_bags):
    r'''
    Instance method to Compute the likelihood given bag labels y_bags and bag probabilities pi.
            Args:
                    pi (torch.Tensor): A tensor representation of the bag probabilities
                    y_bags (torch.Tensor): A tensor representation of the bag labels
            Returns:
                    likelihood (torch.Tensor): A tensor representation of the likelihood

    '''

    z = torch.where(y_bags == -1)[0]
    if z.nelement() > 0:
        zero_sum = torch.sum(torch.log(1 - pi[z] + 1e-10))
    else:
        zero_sum = torch.tensor(0).float()

    o = torch.where(y_bags == 1)[0]
    if o.nelement() > 0:
        one_sum = torch.sum(torch.log(pi[o] + 1e-10))
    else:
        one_sum = torch.tensor(0).float()

    return zero_sum + one_sum

class FeatureExtractor(object):

    r"""
    Object class for building linear or conv feature extractor
    """

    def __init__(self, model_config: Dict):

        r"""
        Initialization function for the class

            Args:
                    model_config (Dict): A dictionary containing model_factory configurations.

            Returns:
                    None
        """

        self.model_config = model_config
        self.build_FE()

    def build_linearFE(self):

        self.feature_extractor = nn.Sequential()

        self.n_features = self.model_config['feature_extractor']['n_features']
        self.dropout_rate = self.model_config['feature_extractor']['dropout_rate']
        self.batch_norm = self.model_config['feature_extractor']['batch_norm']
        self.hidden_activation = self.model_config['feature_extractor']['hidden_activation']
        hidden_neurons = self.model_config['feature_extractor']['hidden_neurons']
        self.layers_neurons_ = [self.n_features, *hidden_neurons]

        for idx, layer in enumerate(self.layers_neurons_[:-1]):
            if self.batch_norm:
                self.feature_extractor.add_module("batch_norm" + str(idx), torch.nn.BatchNorm1d(self.layers_neurons_[idx]))
            self.feature_extractor.add_module("linear" + str(idx),
                                    torch.nn.Linear(self.layers_neurons_[idx], self.layers_neurons_[idx + 1]))
            self.feature_extractor.add_module(self.hidden_activation + str(idx), GetActivation(self.hidden_activation))
            self.feature_extractor.add_module("dropout" + str(idx), torch.nn.Dropout(self.dropout_rate))

    def build_convFE(self):

        r'''
        Instance method for building conv feature extractor module according to config
        '''

        self.feature_extractor_1 = nn.Sequential()
        self.feature_extractor_2 = nn.Sequential()

        hidden_neurons = self.model_config['feature_extractor']['hidden_neurons']
        self.layers_neurons_ = [1, *hidden_neurons]
        self.kernal_size = self.model_config['feature_extractor']['kernal_size']
        self.pool_kernal_size = self.model_config['feature_extractor']['pool_kernal_size']
        self.pool_stride = self.model_config['feature_extractor']['pool_stride']
        self.hidden_activation = self.model_config['feature_extractor']['hidden_activation']

        for idx, layer in enumerate(self.layers_neurons_[:-1]):

            self.feature_extractor_1.add_module("conv" + str(idx),
                nn.Conv2d(self.layers_neurons_[idx], self.layers_neurons_[idx + 1], kernel_size=self.kernal_size))
            self.feature_extractor_1.add_module("hidden_activation" + str(idx), GetActivation(self.hidden_activation))
            self.feature_extractor_1.add_module("pool" + str(idx),
                                    nn.MaxPool2d(self.pool_kernal_size, stride=self.pool_stride))



Complete the function implementation replacing "raise NotImplementedError".