import numpy as np
import pandas as pd
from sklearn.metrics import mean_squared_error, mean_absolute_error
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import LSTM, Dense, LeakyReLU
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.layers import Input
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.ensemble import RandomForestClassifier



years = np.array([[2008], [2016], [2023]])
points = np.array([6, 13, 21])
scaler_years = MinMaxScaler(feature_range=(0, 1))
years_scaled = scaler_years.fit_transform(years)
scaler_points = MinMaxScaler(feature_range=(0, 1))
points_normalized = scaler_points.fit_transform(points.reshape(-1, 1))


lstm_model = Sequential([
    LSTM(100, activation='relu', return_sequences=True, input_shape=(1, 1)),
    LSTM(50, activation='relu'),
    Dense(1)
])
lstm_model.compile(optimizer='adam', loss='mean_squared_error')


lstm_model.fit(years_scaled[:-1], points_normalized[:-1], epochs=1000, batch_size=1, verbose=0)


predicted_points_normalized = lstm_model.predict(years_scaled[-1].reshape(1, 1))
predicted_points = scaler_points.inverse_transform(predicted_points_normalized)[0][0]


mse = mean_squared_error([points[-1]], [predicted_points])
mae = mean_absolute_error([points[-1]], [predicted_points])


print("Mean Squared Error (MSE):", mse)
print("Mean Absolute Error (MAE):", mae)
print("Actual points for 2023:", points[-1])
print("Predicted points for 2023:", predicted_points)




year_2030_scaled = scaler_years.transform(np.array([[2030]]))
predicted_points_2030_normalized = lstm_model.predict(year_2030_scaled)
predicted_points_2030 = scaler_points.inverse_transform(predicted_points_2030_normalized)[0][0]
print("Predicted number of points for 2030:", predicted_points_2030)


existing_points = 21  
new_points = max(0, int(round(predicted_points_2030)) - existing_points)
print("New points to generate for 2030:", new_points)


def load_data(file_path):
    data = pd.read_excel(file_path, header=None)
    data = data.dropna()  
    return data[0].values.reshape(-1, 1)

file_path = r""
depth_data = load_data(file_path)
scaler_depth = MinMaxScaler(feature_range=(0, 1))
depth_data_normalized = scaler_depth.fit_transform(depth_data)


if np.any(np.isnan(depth_data_normalized)):
    raise ValueError("NaN values found in depth data after normalization")


def build_generator(input_dim):
    model = Sequential()
    model.add(Dense(units=50, input_dim=input_dim))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dense(units=1, activation='sigmoid'))  
    return model

def build_discriminator():
    model = Sequential()
    model.add(Dense(units=50, input_dim=1))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dense(units=1, activation='sigmoid'))
    return model

generator = build_generator(100)
discriminator = build_discriminator()
discriminator.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5))
discriminator.trainable = False
gan_input = Input(shape=(100,))
x = generator(gan_input)
gan_output = discriminator(x)
gan = Model(inputs=gan_input, outputs=gan_output)
gan.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5))


batch_size = 32
epochs = 1000
for epoch in range(epochs):

    idx = np.random.randint(0, depth_data_normalized.shape[0], batch_size)
    real_data = depth_data_normalized[idx]


    noise = np.random.normal(0, 1, (batch_size, 100))
    fake_data = generator.predict(noise)


    d_loss_real = discriminator.train_on_batch(real_data, np.ones((batch_size, 1)))
    d_loss_fake = discriminator.train_on_batch(fake_data, np.zeros((batch_size, 1)))
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)


    noise = np.random.normal(0, 1, (batch_size, 100))
    g_loss = gan.train_on_batch(noise, np.ones((batch_size, 1)))


    if epoch % 100 == 0:
        print(f"{epoch}/{epochs} [D loss: {d_loss}] [G loss: {g_loss}]")

noise = np.random.normal(0, 1, (new_points, 100))
generated_data = generator.predict(noise)
generated_data_scaled = scaler_depth.inverse_transform(generated_data)  # 


if np.any(np.isnan(generated_data_scaled)):
    raise ValueError("NaN values found in generated data")


real_labels = np.ones(depth_data.shape[0])
fake_labels = np.zeros(generated_data_scaled.shape[0])
all_data = np.vstack((depth_data, generated_data_scaled))
all_labels = np.concatenate((real_labels, fake_labels))


if np.any(np.isnan(all_data)) or np.any(np.isnan(all_labels)):
    print("Data contains NaN values. Please check the input data.")
else:
  
    X_train, X_test, y_train, y_test = train_test_split(all_data, all_labels, test_size=0.3, random_state=42)
    classifier = RandomForestClassifier()
    classifier.fit(X_train, y_train)
    predictions = classifier.predict(X_test)
    print("GAN Output Classifier Evaluation:\n", classification_report(y_test, predictions))


output_path = r""
pd.DataFrame(generated_data_scaled, columns=['Generated Depth']).to_excel(output_path, index=False)
print("Data generated and saved to", output_path)

import numpy as np
from PIL import Image, ImageDraw


def load_image(image_path):
    """Load an image from the given path."""
    return Image.open(image_path)


def generate_points(image_data, num_simulations=500000):
    if image_data.mode != 'RGB':
        image_data = image_data.convert('RGB')
    image_data = np.array(image_data)

    # Define color ranges for different susceptibility levels
    mask_red = np.all((image_data >= [150, 0, 0]) & (image_data <= [255, 100, 100]), axis=-1)
    mask_orange = np.all((image_data >= [200, 100, 0]) & (image_data <= [255, 160, 100]), axis=-1)
    mask_light_green = np.all((image_data >= [100, 200, 100]) & (image_data <= [150, 255, 150]), axis=-1)
    mask_green = np.all((image_data >= [0, 100, 0]) & (image_data <= [100, 255, 100]), axis=-1)

    # Exclude low susceptibility (deep green) area
    mask_valid = (mask_red | mask_orange | mask_light_green) & ~mask_green
    valid_coords = np.column_stack(np.where(mask_valid))

    # Probabilities
    probabilities = [0.5 if mask_red[y, x] else 0.3 if mask_orange[y, x] else 0.2 for y, x in valid_coords]
    # Normalize probabilities
    probabilities = np.array(probabilities)
    probabilities /= probabilities.sum()

    # Generate points according to the specified probabilities
    total_points = []
    for _ in range(num_simulations):
        index = np.random.choice(len(valid_coords), p=probabilities)
        point = valid_coords[index]
        total_points.append(tuple(point))

    # Count occurrences of each point
    unique_points, counts = np.unique(total_points, axis=0, return_counts=True)
    top_indices = np.argsort(counts)[-7:]
    top_points = unique_points[top_indices]
    top_counts = counts[top_indices]

    return top_points, top_counts


# Load the image from your local path
image_path = r""
image = load_image(image_path)

# Generate points and get the results
top_points, top_counts = generate_points(image)

# Draw the points on the image
draw = ImageDraw.Draw(image)
for point in top_points:
    draw.ellipse((point[1] - 5, point[0] - 5, point[1] + 5, point[0] + 5), fill='black')

# Save or display the image
image.save(r"")
image.show()
