jeudi 9 novembre 2023

I want to display the current media in the lightbox when I click on a media in the gallery [closed]

"I have a code that displays the header, the gallery for each photographer. I managed to display the lightbox when clicking on a media (JSON file containing the necessary data), but the problem is that when I click on any media, it shows the first media from the list and not the selected media. The code javascript is in two files, one containing the lightbox and the other containing the media factory and

State pattern - determining the next state from multiple options

I am implementing a noise gate in Python, using the state design pattern.

My implementation takes an array of audio samples and, using the parameters of the noise gate, the audio sample magnitude values, and the state of the noise gate, determines a coefficient value in the range [0, 1] which should be multiplied with the current audio sample value.

The states I have defined are OpenState, ClosedState, OpeningState and ClosingState. I believe the image below contains all of the state transitions I need to consider.

State transitions

When the gate is in ClosingState, there are two possible transitions:

  1. ClosingState -> ClosedState - this occurs if the release period elapses without another peak exceeding the threshold during that time.
  2. ClosingState -> OpenState - this occurs if a peak exceeds the threshold at some point during the release period.

The part of my code that decides which state to transition to is this method inside the ClosingState class.

def check_if_state_transition_is_due(self, sample_mag: float=0) -> None:        
    '''
    There are two possible states that we can transition to from ClosingState.
    Feels strange to introduce conditionals to determine state transition(?)
    '''
    # This doesn't feel right introducing these conditionals here.
    if sample_mag > self.context.lin_thresh:
        self.transition_pending = True
        self.new_state = OpenState()
        return True
    
    if self.sample_counter >= self.context.release_period_in_samples-1:
        self.transition_pending = True
        self.new_state = ClosedState()
        return True

My question is simply whether it is OK to use these conditionals to determine which state to transition to. It feels like re-introducing the type of code that using the state pattern gets rid of, but an alternative is not obvious to me.


Below is a minimum example. This may not be needed for my conceptual question above, but I am including it in case it is. The sample audio file can be found here.

SO_ramp_functions.py

import numpy as np

def ramp_linear_increase(num_points):
    ''' Function defining a linear increase from 0 to 1 in num_points samples '''
    return np.linspace(0, 1, num_points)

def ramp_linear_decrease(num_points):
    ''' Function defining a linear decrease from 1 to 0 in num_points samples '''
    return np.linspace(1, 0, num_points)

def ramp_poly_increase(num_points):
    ''' Generate an array of coefficient values for the attack period '''
    x = np.arange(num_points, 0, -1)
    attack_coef_arr = 1 - (x/num_points)**4
    
    # Make sure the start and end are 0 and 1, respectively
    attack_coef_arr[0] = 0
    attack_coef_arr[-1] = 1
    
    return attack_coef_arr


def ramp_poly_decrease(num_points):
    ''' Generate an array of coefficient values for the release period '''
    x = np.arange(num_points)
    release_coef_arr = 1 - (x/num_points)**4
    
    # Make sure the start and end are 1 and 0, respectively
    release_coef_arr[0] = 1
    release_coef_arr[-1] = 0
    
    return release_coef_arr

SO_gate_states.py

from abc import ABC, abstractmethod


class State(ABC):
    """
    The base State class declares methods that all concrete States should
    implement and also provides a backreference to the Context object,
    associated with the State. This backreference can be used by States to
    transition the Context to another State.
    """

    @property
    def context(self):
        return self._context


    @context.setter
    def context(self, context) -> None:
        self._context = context


    @abstractmethod
    def get_sample_coefficient(self, sample_mag: float) -> float:
        pass
    
    
    @abstractmethod
    def check_if_state_transition_is_due(self, sample_mag: float=None) -> None:
        pass
    
    
    @abstractmethod
    def on_entry(self):
        pass
    
    
    @abstractmethod
    def on_exit(self):
        pass


"""
Concrete States implement various behaviors, associated with a state of the
Context.
"""

class ClosedState(State):
    
    def __init__(self):
        self.sample_counter = 0
        self.transition_pending = False
    
    
    def get_sample_coefficient(self, sample_mag: float=0) -> float:
        ''' 
        Get the appropriate coefficient value to multiply with the current
        audio sample value.
        
        In the closed state, the coefficient is always 0.0.
        '''
        
        self.transition_pending = self.check_if_state_transition_is_due(sample_mag)
        return 0.0
        
    
    def check_if_state_transition_is_due(self, sample_mag: float=0) -> None:
        '''
        Check if a condition is met that initiates a transition.
        For ClosedState, we want to check if the sample magnitude exceeds the threshold.
        '''
        return sample_mag > self.context.lin_thresh
    
    
    def on_entry(self):
        pass
    
    
    def on_exit(self):
        pass
        
        
    def handle_state_transition(self):
        if self.transition_pending:
            self.context.transition_to(OpeningState())


class OpeningState(State):
    '''
    - In OpeningState, the coefficient is determined by the shape of the
        specified attack ramp.
    
    - The only state we can transition to from OpeningState is OpenState.
    '''
    
    def __init__(self):
        self.sample_counter = 0
        self.transition_pending = False
    
    
    def get_sample_coefficient(self, sample_mag: float=0) -> float:
        
        self.transition_pending = self.check_if_state_transition_is_due()
        if self.transition_pending:
            return 1.0
        else:
            # Get a value from the gate's attack ramp
            return self.context.attack_ramp[self.sample_counter]
        
        
    def check_if_state_transition_is_due(self, sample_mag: float=0) -> None:
        # Transition to OpenState occurs once attack period has elapsed
        return self.sample_counter >= self.context.attack_period_in_samples
    
    
    def handle_state_transition(self):
        if self.transition_pending:
            self.context.transition_to(OpenState())
            self.on_exit()
    
    
    def on_entry(self):
        pass
    
    
    def on_exit(self):
        # This may not be needed, since we construct a new instance when
        # transitioning, but it may make it more robust
        self.sample_counter = 0
    

class OpenState(State):
    '''
    In OpenState, the coefficient is always 1.0.
    The only state we can transition to from OpenState is ClosingState.
    '''
    
    def __init__(self):
        self.sample_counter = 0
        self.transition_pending = False
    
    
    def get_sample_coefficient(self, sample_mag: float=0) -> float:
        self.transition_pending = self.check_if_state_transition_is_due(sample_mag)
        return 1.0
    
    
    def check_if_state_transition_is_due(self, sample_mag: float=0) -> None:
        # The gate can't transition before its hold period has elapsed
        if self.sample_counter < self.context.hold_period_in_samples:
            return False
        else:
            # If the signal magnitude falls below the threshold, we want to
            # transition to ClosingState.
            return sample_mag < self.context.lin_thresh
    
    
    def on_entry(self):
        pass
    
    
    def on_exit(self):
        # This may not be needed, since we construct a new instance when
        # transitioning, but it may make it more robust
        self.sample_counter = 0
        
        
    def handle_state_transition(self):
        if self.transition_pending:
            self.context.transition_to(ClosingState())
            self.on_exit()
    

class ClosingState(State):
    '''    
    - The coefficient is determined by the shape of the specified release ramp.
    - The state can transition to either ClosedState or OpenState.
    '''
    
    def __init__(self):
        self.sample_counter = 0
        self.transition_pending = False
        self.new_state = None
    
    
    def get_sample_coefficient(self, sample_mag: float=0) -> float:
        self.transition_pending = self.check_if_state_transition_is_due(sample_mag)
        return self.context.release_ramp[self.sample_counter]
        
        
    def check_if_state_transition_is_due(self, sample_mag: float=0) -> None:        
        '''
        There are two possible states that we can transition to from ClosingState.
        Feels strange to introduce conditionals to determine state transition(?)
        '''
        # This doesn't feel right introducing these conditionals here.
        if sample_mag > self.context.lin_thresh:
            self.transition_pending = True
            self.new_state = OpenState()
            return True

        if self.sample_counter >= self.context.release_period_in_samples-1:
            self.transition_pending = True
            self.new_state = ClosedState()
            return True
        
        
    def handle_state_transition(self):
        if self.transition_pending:
            self.context.transition_to(self.new_state)
            self.on_exit()
        
        
    def on_entry(self):
        pass
    
    
    def on_exit(self):
        # This may not be needed, since we construct a new instance when
        # transitioning, but it may make it more robust
        self.sample_counter = 0


SO_noise_gate_state_pattern.py

import numpy as np
import SO_ramp_functions as rf

'''
The original template code is found here:
    https://refactoring.guru/design-patterns/state/python/example
'''

class AudioConfig:
    '''
    Values that configure audio playback, so they can be set indepdendently
    of, and shared between, different objects that need them.
    '''
    def __init__(self, fs):
        self.fs = fs


class Context:
    """
    This class represents the noise gate.
    
    The Context defines the interface of interest to clients. It also maintains
    a reference to an instance of a State subclass, which represents the current
    state of the Context.
    """

    def __init__(self, audio_config, state) -> None:
        self.audio_config = audio_config
        self.transition_to(state)
        
        # Specify an initial threshold value in dBFS
        self.thresh = -20
                
        # Specify attack, hold, release, and lookahead periods in seconds
        self.attack_time = 0.005  # seconds
        self.hold_time = 0.05  # seconds
        self.release_time = 0.1  # seconds
        self.lookahead_time = 0.005 # seconds
        
        # Calculate attack, hold, and release periods in samples
        self.attack_period_in_samples = self.seconds_to_samples(self.audio_config.fs, self.attack_time)        
        self.hold_period_in_samples = self.seconds_to_samples(self.audio_config.fs, self.hold_time)
        self.release_period_in_samples = self.seconds_to_samples(self.audio_config.fs, self.release_time)
        self.lookahead_period_in_samples = self.seconds_to_samples(self.audio_config.fs, self.lookahead_time)
        
        # Define the attack and release multiplier ramps - use strategy pattern?
        self.attack_ramp = rf.ramp_poly_increase(num_points=self.attack_period_in_samples)
        self.release_ramp = rf.ramp_poly_decrease(num_points=self.release_period_in_samples)
        
        # Initialise an attribute to store the processed result
        self.processed_array = None
        self.coef_array = None
        
        # Padding to enable lookahead (a bit of a hack)
        self.lookahead_pad_samples = self.lookahead_period_in_samples#2000
        
        # Attributes for debugging
        self.text_output = []


    def transition_to(self, state):
        """
        The Context allows changing the State object at runtime.
        """

        ##print(f"Context: Transition to {type(state).__name__}")
        self._state = state
        self._state.context = self


    # Setters for gate parameters
    def set_attack_time(self, new_attack_time: float) -> None:
        self.attack_time = new_attack_time
        self.attack_period_in_samples = self.seconds_to_samples(self.audio_config.fs, self.attack_time)
    
    
    def set_hold_time(self, new_hold_time: float) -> None:
        self.hold_time = new_hold_time
        self.hold_period_in_samples = self.seconds_to_samples(self.audio_config.fs, self.hold_time)
        
        
    def set_release_time(self, new_release_time: float) -> None:
        self.release_time = new_release_time
        self.release_period_in_samples = self.seconds_to_samples(self.audio_config.fs, self.release_time)


    @property
    def thresh(self) -> int:
        return self._thresh
    
    
    @thresh.setter
    def thresh(self, new_thresh: int) -> None:
        self._thresh = new_thresh


    @property
    def lin_thresh(self) -> float:
        return self.dBFS_to_lin(self.thresh)
    
    
    # These staticmethods could equally be defined outside the class
    @staticmethod
    def dBFS_to_lin(dBFS_val):
        ''' Helper method to convert a dBFS value to a linear value [0, 1] '''
        return 10 ** (dBFS_val / 20)
        

    @staticmethod
    def seconds_to_samples(fs, seconds_val):
        ''' Helper method to convert a time (seconds) value to a number of samples '''
        return int(fs * seconds_val)

    
    def process_audio_block(self, audio_array=None):
        '''
        Process an array of audio samples according to the gate's parameters,
        current state, and the sample values in the audio array.
        This implementation includes lookahead logic.
        
        '''
        
        # Initialise an array of coefficient values of the same length as audio_array
        # Set initial coefficient values outside valid range [0, 1] for easier debugging
        self.coef_array = np.ones(len(audio_array))[:-self.lookahead_pad_samples] * 2
        # Get the magnitude values of the audio array
        self.mag_array = np.abs(audio_array)

        # Iterate through the samples of the mag_arr, updating coef_array values
        for i, sample_mag in enumerate(self.mag_array[:-self.lookahead_pad_samples]):    
            # Get the coefficient value for the current sample, considering a lookahead period
            self.coef_array[i] = self._state.get_sample_coefficient(self.mag_array[i + self.lookahead_period_in_samples])
            # Increment the counter for tracking the samples elapsed in the current state
            self._state.sample_counter += 1
            # Create a log of the state and samples elapsed, for debugging
            self.text_output.append(f"{type(self._state).__name__}. {self._state.sample_counter}. {self.coef_array[i]:.3f}")
            # After processing the current sample, check if a transition is due
            self._state.handle_state_transition()
            
        self.processed_array = self.coef_array * audio_array[:-self.lookahead_pad_samples]

main.py

'''
Driver code for the noise gate using the state pattern.

'''

from SO_noise_gate_state_pattern import AudioConfig, Context
from SO_gate_states import ClosedState
import numpy as np
import audiofile
import matplotlib.pyplot as plt
import time


# Define some helper/test functions
def load_audio(fpath):
    data, fs = audiofile.read(fpath)
    data = data.T
    if len(data.shape) == 2:
        data = data[:,0]    # convert to mono
    return data


def test_gate_coef_values_are_valid(coef_arr):
    print("Testing gate coef_array values")
    assert(np.all([0<=val<=1 for val in coef_arr]))


if __name__ == "__main__":
    
    # The client code.
    # Configure some audio properties
    audio_config = AudioConfig(fs=44100)
    
    # Create a "context" instance (this is like the NoiseGate class)
    context = Context(audio_config, ClosedState())
    
    # Load audio from file
    sig = load_audio(fpath="./snare_test.wav")
    # Zero-pad the audio array to enable lookahead (experimental)
    sig = np.concatenate((sig, np.zeros(context.lookahead_pad_samples)))
    
    # Process the whole array and time it
    start_time = time.perf_counter()
    context.process_audio_block(sig)
    end_time = time.perf_counter()
    print(f"Time taken to process {len(sig)/audio_config.fs:.2f} seconds of audio: {end_time - start_time:.2f} seconds")
    
    # Some testing on the result
    test_gate_coef_values_are_valid(context.coef_array)
    
    # Plot the result
    plt.plot(context.mag_array, color='blue', linewidth=1, label='signal magnitude')
    plt.plot(context.coef_array, color='green', label='gate coefficient')
    plt.plot(np.abs(context.processed_array), color='orange', label='gate output')
    plt.axhline(context.lin_thresh, color='black', linewidth=1, label='gate threshold')
    plt.legend()
    plt.show()

mercredi 8 novembre 2023

Which pattern would you use to implement an "early-termination" logic?

In my project, I have several occurrences that needs verification on value using multiple conditions. Since satisfying at least one of these "conditions" is enough, and each conditions require heavy computation power, I usually try from the most lightweight one to the heaviest one, until any of them succeeds. To implement this, I usually use a pattern like below.

bool success

do {
    if (success = condition_1()) break
    if (success = condition_2()) break
    ...
} while (false)

if (!success) {
    cleanup()
} else {
    proceed()
}

The point is that I want to use the "break" statement, but to do this, I have to add a dummy do-while loop, which actually does nothing but provides context for the break statement. I doubt if doing so is okay. Would anybody have a recommendation for a better pattern on this situation?

These are the patterns I've tried as workarounds.

  • Separate the condition checks as a function, and using return statements instead of break => This is good, but sometimes I don't want to make too many functions.
  • Declare a common flag that indicates success, and run each condition if the flag is set false => This requires evaluation of if statements on each step, although their impacts on performance are minuscule.

Abstract class vs Factory bridge design pattern C# example [closed]

I'm making an imaging desktop application using Windows Form in C# .NETFramework. The application main task is to process and visualize images form an images stack. I can have a single stack or two of them combined, some processing steps are gonna be done on every Image before visualization and others when reading from the stacks depending on the input data. This is a simple prototype with abstract classes, how can it be written using Factory-Bridge Design pattern?

class:

public abstract class Mstack
{
    public abstract int GetLen();
    public abstract Image<Gray, float> GetImage(int i);
}
public class MBaseStackClass<TDepth> : Mstack where TDepth : new ()
{
    Image<Gray, TDepth>[] data;
    int len;
    public MBaseStackClass(Image<Gray, TDepth>[] data)
    {
        this.data = data;
        len = data.Length;

    }
    override public Image<Gray, float> GetImage(int i)
    {
        return data[i].Convert<Gray, float>();
    }
    public override int GetLen()
    {
        return len;
    }
}
public class MDEStackClass : Mstack
{
    public enum viewmode { high_en, low_en, divide }
    private viewmode vm = viewmode.high_en;
    Mstack stlow;
    Mstack sthigh;

    public MDEStackClass(Mstack stlow, Mstack sthigh)
    {
        this.stlow = stlow;
        this.sthigh = sthigh;
        if(stlow.GetLen() != sthigh.GetLen()) { throw new Exception("Length must be equal"); }
    }


    override public Image<Gray, float> GetImage(int i)
    {
        switch (vm)
        {
            case viewmode.high_en: 
                return sthigh.GetImage(i);
            case viewmode.low_en:
                return stlow.GetImage(i);
            case viewmode.divide:
                return combine(i);
            default:
                return null;
        }
    }
    public override int GetLen()
    {
        return sthigh.GetLen();
    }
    public void set_viewmode(viewmode vmin)
    {
        vm = vmin;
    }
     
    private Image<Gray, float> combine(int i)//division
    {
        return stlow.GetImage(GetLen() - i-1).Mul(sthigh.GetImage(i).Pow(-1));
    }

}

Implementation in main program:


        private void openCEToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Stopwatch st = new Stopwatch();
            st.Start();
            stackManager = new MDEStackClass(
                new MBaseStackClass<ushort>((new ReadImageUser()).readFromCeflaFbpFolder(0)),
                new MBaseStackClass<ushort>((new ReadImageUser()).readFromCeflaFbpFolder(1))
                );
            trackBar1.Maximum = stackManager.GetLen() - 1;
            st.Stop();
            Console.WriteLine(st.ElapsedMilliseconds);
            GC.Collect();
        }
        viewmode vm = viewmode.divide;
        public void show_image(int i)
        {
            stackManager.set_viewmode(vm);
            //for the future image processing goes like: pictureBox1.Image = img_processing(stackManager.GetImage(i)).Resize(...).ToBitmap();
            pictureBox1.Image = (stackManager.GetImage(i)).Resize(pictureBox1.Width, pictureBox1.Height, Emgu.CV.CvEnum.Inter.Cubic).ToBitmap();
            pictureBox1.Refresh();
            GC.Collect();
        }

Builder Pattern : Can our director deal with Concrete builders directly?

I was reading builder design pattern and have the following doubt - Why director cannot accept the concrete builder type reference ?

Suppose, we have a CarBuilder interface which implemented by 2 concrete builders SUVCarBuilder and SportsCarBuilder . We see that our Director class is like -

public class Director {

    public void constructSportsCar(Builder builder) {
        builder.setCarType(CarType.SPORTS_CAR);
        builder.setSeats(2);
        builder.setEngine(new Engine(3.0, 0));
        builder.setTransmission(Transmission.SEMI_AUTOMATIC);
        builder.setTripComputer(new TripComputer());
        builder.setGPSNavigator(new GPSNavigator());
    }

    public void constructSUV(Builder builder) {
        builder.setCarType(CarType.SUV);
        builder.setSeats(4);
        builder.setEngine(new Engine(2.5, 0));
        builder.setTransmission(Transmission.MANUAL);
        builder.setGPSNavigator(new GPSNavigator());
    }
}

The methods accept Builder type rather than concrete types - SUVCarBuilder and SportsCarBuilder. Can our director not accept ConcreteBuilders types ? That way, we can even return the concrete product from director itself.

public class Director {

    public SportsCar constructSportsCar(SportsCarBuilder builder) {
        builder.setCarType(CarType.SPORTS_CAR);
        builder.setSeats(2);
        builder.setEngine(new Engine(3.0, 0));
        builder.setTransmission(Transmission.SEMI_AUTOMATIC);
        builder.setTripComputer(new TripComputer());
        builder.setGPSNavigator(new GPSNavigator());
        // Get the concrete product
        return builder.getSportsCar();
    }

    public SUVCar constructSUV(SUVCarBuilder builder) {
        builder.setCarType(CarType.SUV);
        builder.setSeats(4);
        builder.setEngine(new Engine(2.5, 0));
        builder.setTransmission(Transmission.MANUAL);
        builder.setGPSNavigator(new GPSNavigator());
        // Get the concrete product
        return builder.getSUVCar();
    }
}

Where to fetch data for permissions in Clean Architecture?

Using Clean Architecture I need to implement permissions.

I decided to implement additional permissions layer PermissionsChecker. My permissions depend on database state. I have assigned permissions to the user in database as well as it depends on the state of the domain object. I have adapter for my database. Now where should I fetch data using that adapter?

  1. Should I fetch data on the use case level and pass it down to the PermissionChecker?
  2. Or Should I fetch data on the permission layer? But then PermissionChecker would have dependency to database port.
  3. Or other solution that I didn't think of?

mardi 7 novembre 2023

Will it break SOLID principle?

trying to write a generic method which get called and based on object type it should set indicators.

  1. will it break solid principle?
  2. is there any better way of doing it.

i was working on one of the feature where i have 3 line of business like Car, van and bike. I have IVechile interface which is handling all the common implementation between 3 Line of business.

Now, i have to set two common indicator Car and Van but for bike i want to set some different indicator. I want to create a object of this class once but it handle based on type of line business. If write this method like this will it break SOLID principle? If it is incorrect please suggest me something?

Note: INDICATOR_B should be true in all LOB

function populateIndicator() {
  if (_motorObject typeis Car or _motorObject typeis entity.Van) {
    _motorObject.INDICATOR_A = true
  }
  if (_motorObject typeis Bike) {
    _motorObject.INDICATOR_C = true
  }
  _motorObject.INDICATOR_B = true
}