use crate::error::{OptimError, Result};
use chrono::{DateTime, TimeZone, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConferenceManager {
pub conferences: HashMap<String, Conference>,
pub submissions: Vec<Submission>,
pub alerts: Vec<DeadlineAlert>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Conference {
pub id: String,
pub name: String,
pub abbreviation: String,
pub description: String,
pub url: String,
pub ranking: ConferenceRanking,
pub research_areas: Vec<String>,
pub annual: bool,
pub series_info: SeriesInfo,
pub dates: ConferenceDates,
pub requirements: SubmissionRequirements,
pub review_process: ReviewProcess,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ConferenceRanking {
TopTier,
HighQuality,
Good,
Acceptable,
Emerging,
Workshop,
Unranked,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SeriesInfo {
pub series_number: u32,
pub year: u32,
pub location: String,
pub country: String,
pub format: ConferenceFormat,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ConferenceFormat {
InPerson,
Virtual,
Hybrid,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConferenceDates {
pub abstract_deadline: Option<DateTime<Utc>>,
pub paper_deadline: DateTime<Utc>,
pub notification_date: DateTime<Utc>,
pub camera_ready_deadline: DateTime<Utc>,
pub conference_start: DateTime<Utc>,
pub conference_end: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubmissionRequirements {
pub page_limit: u32,
pub word_limit: Option<u32>,
pub format: FormatRequirements,
pub required_sections: Vec<String>,
pub supplementary_allowed: bool,
pub anonymous_submission: bool,
pub double_blind: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FormatRequirements {
pub template: String,
pub font_size: u32,
pub line_spacing: f64,
pub margins: String,
pub citation_style: String,
pub file_format: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReviewProcess {
pub reviewers_per_paper: u32,
pub review_criteria: Vec<String>,
pub rebuttal_allowed: bool,
pub acceptance_rate: Option<f64>,
pub review_format: ReviewFormat,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ReviewFormat {
NumericalScores,
WrittenOnly,
Mixed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Submission {
pub id: String,
pub conference_id: String,
pub paper_id: String,
pub status: SubmissionStatus,
pub submitted_at: DateTime<Utc>,
pub track: Option<String>,
pub materials: SubmissionMaterials,
pub reviews: Vec<Review>,
pub decision: Option<Decision>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum SubmissionStatus {
Draft,
Submitted,
UnderReview,
Rebuttal,
Decided,
CameraReady,
Withdrawn,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubmissionMaterials {
pub paper_file: String,
pub supplementary_files: Vec<String>,
pub abstracttext: String,
pub keywords: Vec<String>,
pub authors: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Review {
pub id: String,
pub reviewer: String,
pub overall_score: Option<f64>,
pub detailed_scores: HashMap<String, f64>,
pub reviewtext: String,
pub recommendation: ReviewRecommendation,
pub reviewed_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ReviewRecommendation {
StrongAccept,
Accept,
WeakAccept,
Borderline,
WeakReject,
Reject,
StrongReject,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Decision {
pub outcome: DecisionOutcome,
pub decided_at: DateTime<Utc>,
pub editor_comments: Option<String>,
pub required_revisions: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum DecisionOutcome {
Accept,
AcceptMinorRevisions,
AcceptMajorRevisions,
ConditionalAccept,
Reject,
RejectAndResubmit,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeadlineAlert {
pub id: String,
pub conference_id: String,
pub deadline_type: DeadlineType,
pub alert_date: DateTime<Utc>,
pub days_before: u32,
pub message: String,
pub sent: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum DeadlineType {
AbstractSubmission,
PaperSubmission,
Notification,
CameraReady,
ConferenceStart,
}
impl Default for ConferenceManager {
fn default() -> Self {
Self::new()
}
}
impl ConferenceManager {
pub fn new() -> Self {
Self {
conferences: HashMap::new(),
submissions: Vec::new(),
alerts: Vec::new(),
}
}
pub fn add_conference(&mut self, conference: Conference) {
self.conferences.insert(conference.id.clone(), conference);
}
pub fn submit_paper(
&mut self,
conference_id: &str,
paper_id: &str,
materials: SubmissionMaterials,
) -> Result<String> {
if !self.conferences.contains_key(conference_id) {
return Err(OptimError::InvalidConfig(format!(
"Conference '{}' not found",
conference_id
)));
}
let submission_id = uuid::Uuid::new_v4().to_string();
let submission = Submission {
id: submission_id.clone(),
conference_id: conference_id.to_string(),
paper_id: paper_id.to_string(),
status: SubmissionStatus::Submitted,
submitted_at: Utc::now(),
track: None,
materials,
reviews: Vec::new(),
decision: None,
};
self.submissions.push(submission);
Ok(submission_id)
}
pub fn get_upcoming_deadlines(
&self,
days_ahead: u32,
) -> Vec<(&Conference, DeadlineType, DateTime<Utc>)> {
let mut deadlines = Vec::new();
let now = Utc::now();
let future_limit = now + chrono::Duration::days(days_ahead as i64);
for conference in self.conferences.values() {
let dates = &conference.dates;
if let Some(abstract_deadline) = dates.abstract_deadline {
if abstract_deadline > now && abstract_deadline <= future_limit {
deadlines.push((
conference,
DeadlineType::AbstractSubmission,
abstract_deadline,
));
}
}
if dates.paper_deadline > now && dates.paper_deadline <= future_limit {
deadlines.push((
conference,
DeadlineType::PaperSubmission,
dates.paper_deadline,
));
}
if dates.notification_date > now && dates.notification_date <= future_limit {
deadlines.push((
conference,
DeadlineType::Notification,
dates.notification_date,
));
}
if dates.camera_ready_deadline > now && dates.camera_ready_deadline <= future_limit {
deadlines.push((
conference,
DeadlineType::CameraReady,
dates.camera_ready_deadline,
));
}
if dates.conference_start > now && dates.conference_start <= future_limit {
deadlines.push((
conference,
DeadlineType::ConferenceStart,
dates.conference_start,
));
}
}
deadlines.sort_by_key(|a| a.2);
deadlines
}
pub fn search_conferences(&self, research_area: &str) -> Vec<&Conference> {
self.conferences
.values()
.filter(|conf| {
conf.research_areas
.iter()
.any(|area| area.to_lowercase().contains(&research_area.to_lowercase()))
})
.collect()
}
pub fn get_conferences_by_ranking(&self, ranking: ConferenceRanking) -> Vec<&Conference> {
self.conferences
.values()
.filter(|conf| conf.ranking == ranking)
.collect()
}
pub fn load_standard_conferences(&mut self) {
self.add_conference(Self::create_neurips_conference());
self.add_conference(Self::create_icml_conference());
self.add_conference(Self::create_iclr_conference());
self.add_conference(Self::create_aaai_conference());
self.add_conference(Self::create_ijcai_conference());
}
fn create_neurips_conference() -> Conference {
Conference {
id: "neurips2024".to_string(),
name: "Conference on Neural Information Processing Systems".to_string(),
abbreviation: "NeurIPS".to_string(),
description: "Premier conference on neural information processing systems".to_string(),
url: "https://neurips.cc/".to_string(),
ranking: ConferenceRanking::TopTier,
research_areas: vec![
"Machine Learning".to_string(),
"Deep Learning".to_string(),
"Neural Networks".to_string(),
"Optimization".to_string(),
],
annual: true,
series_info: SeriesInfo {
series_number: 38,
year: 2024,
location: "Vancouver".to_string(),
country: "Canada".to_string(),
format: ConferenceFormat::Hybrid,
},
dates: ConferenceDates {
abstract_deadline: Some(
chrono::Utc
.with_ymd_and_hms(2024, 5, 15, 23, 59, 59)
.single()
.expect("invalid datetime"),
),
paper_deadline: chrono::Utc
.with_ymd_and_hms(2024, 5, 22, 23, 59, 59)
.single()
.expect("invalid datetime"),
notification_date: chrono::Utc
.with_ymd_and_hms(2024, 9, 25, 12, 0, 0)
.single()
.expect("invalid datetime"),
camera_ready_deadline: chrono::Utc
.with_ymd_and_hms(2024, 10, 30, 23, 59, 59)
.single()
.expect("invalid datetime"),
conference_start: chrono::Utc
.with_ymd_and_hms(2024, 12, 10, 9, 0, 0)
.single()
.expect("invalid datetime"),
conference_end: chrono::Utc
.with_ymd_and_hms(2024, 12, 16, 18, 0, 0)
.single()
.expect("invalid datetime"),
},
requirements: SubmissionRequirements {
page_limit: 9,
word_limit: None,
format: FormatRequirements {
template: "NeurIPS 2024 LaTeX template".to_string(),
font_size: 10,
line_spacing: 1.0,
margins: "1 inch".to_string(),
citation_style: "NeurIPS".to_string(),
file_format: vec!["PDF".to_string()],
},
required_sections: vec![
"Abstract".to_string(),
"Introduction".to_string(),
"Related Work".to_string(),
"Method".to_string(),
"Experiments".to_string(),
"Conclusion".to_string(),
],
supplementary_allowed: true,
anonymous_submission: true,
double_blind: true,
},
review_process: ReviewProcess {
reviewers_per_paper: 3,
review_criteria: vec![
"Technical Quality".to_string(),
"Novelty".to_string(),
"Significance".to_string(),
"Clarity".to_string(),
],
rebuttal_allowed: true,
acceptance_rate: Some(0.26), review_format: ReviewFormat::Mixed,
},
}
}
fn create_icml_conference() -> Conference {
Conference {
id: "icml2024".to_string(),
name: "International Conference on Machine Learning".to_string(),
abbreviation: "ICML".to_string(),
description: "Premier international conference on machine learning".to_string(),
url: "https://icml.cc/".to_string(),
ranking: ConferenceRanking::TopTier,
research_areas: vec![
"Machine Learning".to_string(),
"Optimization".to_string(),
"Statistical Learning".to_string(),
"Deep Learning".to_string(),
],
annual: true,
series_info: SeriesInfo {
series_number: 41,
year: 2024,
location: "Vienna".to_string(),
country: "Austria".to_string(),
format: ConferenceFormat::Hybrid,
},
dates: ConferenceDates {
abstract_deadline: None,
paper_deadline: chrono::Utc
.with_ymd_and_hms(2024, 2, 1, 23, 59, 59)
.single()
.expect("invalid datetime"),
notification_date: chrono::Utc
.with_ymd_and_hms(2024, 5, 1, 12, 0, 0)
.single()
.expect("invalid datetime"),
camera_ready_deadline: chrono::Utc
.with_ymd_and_hms(2024, 6, 1, 23, 59, 59)
.single()
.expect("invalid datetime"),
conference_start: chrono::Utc
.with_ymd_and_hms(2024, 7, 21, 9, 0, 0)
.single()
.expect("invalid datetime"),
conference_end: chrono::Utc
.with_ymd_and_hms(2024, 7, 27, 18, 0, 0)
.single()
.expect("invalid datetime"),
},
requirements: SubmissionRequirements {
page_limit: 8,
word_limit: None,
format: FormatRequirements {
template: "ICML 2024 LaTeX template".to_string(),
font_size: 10,
line_spacing: 1.0,
margins: "1 inch".to_string(),
citation_style: "ICML".to_string(),
file_format: vec!["PDF".to_string()],
},
required_sections: vec![
"Abstract".to_string(),
"Introduction".to_string(),
"Methods".to_string(),
"Results".to_string(),
"Conclusion".to_string(),
],
supplementary_allowed: true,
anonymous_submission: true,
double_blind: true,
},
review_process: ReviewProcess {
reviewers_per_paper: 3,
review_criteria: vec![
"Technical Quality".to_string(),
"Clarity".to_string(),
"Originality".to_string(),
"Significance".to_string(),
],
rebuttal_allowed: true,
acceptance_rate: Some(0.23), review_format: ReviewFormat::Mixed,
},
}
}
fn create_iclr_conference() -> Conference {
Conference {
id: "iclr2024".to_string(),
name: "International Conference on Learning Representations".to_string(),
abbreviation: "ICLR".to_string(),
description: "Conference focused on learning representations".to_string(),
url: "https://iclr.cc/".to_string(),
ranking: ConferenceRanking::TopTier,
research_areas: vec![
"Deep Learning".to_string(),
"Representation Learning".to_string(),
"Neural Networks".to_string(),
"Optimization".to_string(),
],
annual: true,
series_info: SeriesInfo {
series_number: 12,
year: 2024,
location: "Vienna".to_string(),
country: "Austria".to_string(),
format: ConferenceFormat::Hybrid,
},
dates: ConferenceDates {
abstract_deadline: Some(
chrono::Utc
.with_ymd_and_hms(2023, 9, 28, 23, 59, 59)
.single()
.expect("invalid datetime"),
),
paper_deadline: chrono::Utc
.with_ymd_and_hms(2023, 10, 2, 23, 59, 59)
.single()
.expect("invalid datetime"),
notification_date: chrono::Utc
.with_ymd_and_hms(2024, 1, 15, 12, 0, 0)
.single()
.expect("invalid datetime"),
camera_ready_deadline: chrono::Utc
.with_ymd_and_hms(2024, 2, 29, 23, 59, 59)
.single()
.expect("invalid datetime"),
conference_start: chrono::Utc
.with_ymd_and_hms(2024, 5, 7, 9, 0, 0)
.single()
.expect("invalid datetime"),
conference_end: chrono::Utc
.with_ymd_and_hms(2024, 5, 11, 18, 0, 0)
.single()
.expect("invalid datetime"),
},
requirements: SubmissionRequirements {
page_limit: 9,
word_limit: None,
format: FormatRequirements {
template: "ICLR 2024 LaTeX template".to_string(),
font_size: 10,
line_spacing: 1.0,
margins: "1 inch".to_string(),
citation_style: "ICLR".to_string(),
file_format: vec!["PDF".to_string()],
},
required_sections: vec![
"Abstract".to_string(),
"Introduction".to_string(),
"Related Work".to_string(),
"Method".to_string(),
"Experiments".to_string(),
"Conclusion".to_string(),
],
supplementary_allowed: true,
anonymous_submission: true,
double_blind: true,
},
review_process: ReviewProcess {
reviewers_per_paper: 3,
review_criteria: vec![
"Technical Quality".to_string(),
"Clarity".to_string(),
"Originality".to_string(),
"Significance".to_string(),
],
rebuttal_allowed: true,
acceptance_rate: Some(0.31), review_format: ReviewFormat::Mixed,
},
}
}
fn create_aaai_conference() -> Conference {
Conference {
id: "aaai2024".to_string(),
name: "AAAI Conference on Artificial Intelligence".to_string(),
abbreviation: "AAAI".to_string(),
description: "Conference on artificial intelligence".to_string(),
url: "https://aaai.org/".to_string(),
ranking: ConferenceRanking::TopTier,
research_areas: vec![
"Artificial Intelligence".to_string(),
"Machine Learning".to_string(),
"Knowledge Representation".to_string(),
"Planning".to_string(),
],
annual: true,
series_info: SeriesInfo {
series_number: 38,
year: 2024,
location: "Vancouver".to_string(),
country: "Canada".to_string(),
format: ConferenceFormat::Hybrid,
},
dates: ConferenceDates {
abstract_deadline: Some(
chrono::Utc
.with_ymd_and_hms(2023, 8, 15, 23, 59, 59)
.single()
.expect("invalid datetime"),
),
paper_deadline: chrono::Utc
.with_ymd_and_hms(2023, 8, 19, 23, 59, 59)
.single()
.expect("invalid datetime"),
notification_date: chrono::Utc
.with_ymd_and_hms(2023, 12, 9, 12, 0, 0)
.single()
.expect("invalid datetime"),
camera_ready_deadline: chrono::Utc
.with_ymd_and_hms(2024, 1, 15, 23, 59, 59)
.single()
.expect("invalid datetime"),
conference_start: chrono::Utc
.with_ymd_and_hms(2024, 2, 20, 9, 0, 0)
.single()
.expect("invalid datetime"),
conference_end: chrono::Utc
.with_ymd_and_hms(2024, 2, 27, 18, 0, 0)
.single()
.expect("invalid datetime"),
},
requirements: SubmissionRequirements {
page_limit: 7,
word_limit: None,
format: FormatRequirements {
template: "AAAI 2024 LaTeX template".to_string(),
font_size: 10,
line_spacing: 1.0,
margins: "0.75 inch".to_string(),
citation_style: "AAAI".to_string(),
file_format: vec!["PDF".to_string()],
},
required_sections: vec![
"Abstract".to_string(),
"Introduction".to_string(),
"Related Work".to_string(),
"Approach".to_string(),
"Experiments".to_string(),
"Conclusion".to_string(),
],
supplementary_allowed: false,
anonymous_submission: true,
double_blind: true,
},
review_process: ReviewProcess {
reviewers_per_paper: 3,
review_criteria: vec![
"Technical Quality".to_string(),
"Novelty".to_string(),
"Significance".to_string(),
"Clarity".to_string(),
],
rebuttal_allowed: false,
acceptance_rate: Some(0.23), review_format: ReviewFormat::NumericalScores,
},
}
}
fn create_ijcai_conference() -> Conference {
Conference {
id: "ijcai2024".to_string(),
name: "International Joint Conference on Artificial Intelligence".to_string(),
abbreviation: "IJCAI".to_string(),
description: "International conference on artificial intelligence".to_string(),
url: "https://ijcai.org/".to_string(),
ranking: ConferenceRanking::TopTier,
research_areas: vec![
"Artificial Intelligence".to_string(),
"Machine Learning".to_string(),
"Automated Reasoning".to_string(),
"Multi-agent Systems".to_string(),
],
annual: true,
series_info: SeriesInfo {
series_number: 33,
year: 2024,
location: "Jeju".to_string(),
country: "South Korea".to_string(),
format: ConferenceFormat::Hybrid,
},
dates: ConferenceDates {
abstract_deadline: Some(
chrono::Utc
.with_ymd_and_hms(2024, 1, 17, 23, 59, 59)
.single()
.expect("invalid datetime"),
),
paper_deadline: chrono::Utc
.with_ymd_and_hms(2024, 1, 24, 23, 59, 59)
.single()
.expect("invalid datetime"),
notification_date: chrono::Utc
.with_ymd_and_hms(2024, 4, 16, 12, 0, 0)
.single()
.expect("invalid datetime"),
camera_ready_deadline: chrono::Utc
.with_ymd_and_hms(2024, 5, 15, 23, 59, 59)
.single()
.expect("invalid datetime"),
conference_start: chrono::Utc
.with_ymd_and_hms(2024, 8, 3, 9, 0, 0)
.single()
.expect("invalid datetime"),
conference_end: chrono::Utc
.with_ymd_and_hms(2024, 8, 9, 18, 0, 0)
.single()
.expect("invalid datetime"),
},
requirements: SubmissionRequirements {
page_limit: 7,
word_limit: None,
format: FormatRequirements {
template: "IJCAI 2024 LaTeX template".to_string(),
font_size: 10,
line_spacing: 1.0,
margins: "0.75 inch".to_string(),
citation_style: "IJCAI".to_string(),
file_format: vec!["PDF".to_string()],
},
required_sections: vec![
"Abstract".to_string(),
"Introduction".to_string(),
"Background".to_string(),
"Approach".to_string(),
"Experiments".to_string(),
"Conclusion".to_string(),
],
supplementary_allowed: false,
anonymous_submission: true,
double_blind: true,
},
review_process: ReviewProcess {
reviewers_per_paper: 3,
review_criteria: vec![
"Technical Quality".to_string(),
"Novelty".to_string(),
"Significance".to_string(),
"Clarity".to_string(),
],
rebuttal_allowed: true,
acceptance_rate: Some(0.15), review_format: ReviewFormat::Mixed,
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_conference_manager_creation() {
let manager = ConferenceManager::new();
assert!(manager.conferences.is_empty());
assert!(manager.submissions.is_empty());
}
#[test]
fn test_load_standard_conferences() {
let mut manager = ConferenceManager::new();
manager.load_standard_conferences();
assert!(manager.conferences.contains_key("neurips2024"));
assert!(manager.conferences.contains_key("icml2024"));
assert!(manager.conferences.contains_key("iclr2024"));
assert!(manager.conferences.contains_key("aaai2024"));
assert!(manager.conferences.contains_key("ijcai2024"));
}
#[test]
fn test_search_conferences() {
let mut manager = ConferenceManager::new();
manager.load_standard_conferences();
let ml_conferences = manager.search_conferences("Machine Learning");
assert!(!ml_conferences.is_empty());
let top_tier = manager.get_conferences_by_ranking(ConferenceRanking::TopTier);
assert!(!top_tier.is_empty());
}
}